diff options
author | Clément Malléjac <clementmallejac@gmail.com> | 2018-07-27 17:05:53 +0200 |
---|---|---|
committer | Clément Malléjac <clementmallejac@gmail.com> | 2018-08-22 11:33:44 +0200 |
commit | 7697648397638b082ce3d3d824c8c128490fc7ce (patch) | |
tree | 9dd46cf134acabd57f90492b8d2f3be7bd7fe63c | |
parent | 92f0e16392712fb80954426722675292d551bf0c (diff) |
Setup the project for afb-test framework
Wrote a couple of basic API tests
Setup mock apis for the test binding
Added script to launch tests on native Linux machines
Change-Id: I606752e7b46cb2afdc10f3319a24ef15675faa3b
Signed-off-by: Clément Malléjac <clementmallejac@gmail.com>
19 files changed, 885 insertions, 15 deletions
diff --git a/conf.d/app-templates b/conf.d/app-templates -Subproject f94e45e8a48e16e3001cb55c4f8c3c0a2a2c9e2 +Subproject f0b24b0809e1677665760d4341a4169d519079b diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 446534c..d009d0b 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -78,7 +78,7 @@ set (PKG_REQUIRED_LIST # Prefix path where will be installed the files # Default: /usr/local (need root permission to write in) # ------------------------------------------------------ -set(INSTALL_PREFIX $ENV{HOME}/opt) +set(INSTALL_PREFIX $ENV{HOME}/opt/AGL) # Customize link option # ----------------------------- @@ -112,10 +112,10 @@ list(APPEND link_libraries afb-helpers) # -pg # -Wp,-U_FORTIFY_SOURCE # CACHE STRING "Compilation flags for PROFILING build type.") -#set(DEBUG_COMPILE_OPTIONS -# -g -# -ggdb -# -Wp,-U_FORTIFY_SOURCE +# set(DEBUG_COMPILE_OPTIONS +# -g +# -ggdb +# -Wp,-U_FORTIFY_SOURCE # CACHE STRING "Compilation flags for DEBUG build type.") #set(CCOV_COMPILE_OPTIONS # -g diff --git a/conf.d/project/data/CMakeLists.txt b/conf.d/project/data/CMakeLists.txt index 5c6a41b..419aba4 100644 --- a/conf.d/project/data/CMakeLists.txt +++ b/conf.d/project/data/CMakeLists.txt @@ -31,13 +31,3 @@ PROJECT_TARGET_ADD(lua.d) OUTPUT_NAME ${TARGET_NAME} ) -PROJECT_TARGET_ADD(openxc-traces) - - file(GLOB OPENXC_FILES "*.json") - - add_input_files("${OPENXC_FILES}") - - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - LABELS "DATA" - OUTPUT_NAME ${TARGET_NAME} - ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..f4d72ac --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,27 @@ +########################################################################### +# Copyright 2015 - 2018 IoT.bzh +# +# author: Clément MAlléjac <clementmallejac@gmail.com> +# +# 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. +########################################################################### + + +# Include any directory not starting with _ +# ----------------------------------------------------- +PROJECT_SUBDIRS_ADD(${PROJECT_SRC_DIR_PATTERN}) + +ADD_TEST(NAME AGL_SERVICE_SIGNAL_COMPOSER_TESTS + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND afb-test.sh ${CMAKE_BINARY_DIR} +)
\ No newline at end of file diff --git a/test/afb-test.sh b/test/afb-test.sh new file mode 100755 index 0000000..96733bf --- /dev/null +++ b/test/afb-test.sh @@ -0,0 +1,41 @@ +#!/bin/sh +trap "cleanup 0" EXIT +trap "cleanup 1" SIGHUP SIGINT SIGABRT SIGTERM +cleanup() { + rm -f $LOGPIPE + echo "Removing $LOGPIPE" + trap '' EXIT SIGHUP SIGINT SIGABRT SIGTERM + exit $1 +} + +BINDER=$(command -v afb-daemon) +AFBTEST="$(pkg-config --variable libdir afb-test)/aft.so" +PROCNAME="aft-signal-composer" +PORT=1234 +TOKEN= +LOGPIPE="test.pipe" +[ "$1" ] && BUILDDIR="$1" || exit 1 + +TESTPACKAGEDIR="${BUILDDIR}/package-test" +[ ! -p $LOGPIPE ] && mkfifo $LOGPIPE +export AFT_CONFIG_PATH="${TESTPACKAGEDIR}/etc" +export AFT_PLUGIN_PATH="${TESTPACKAGEDIR}/var:${TESTPACKAGEDIR}/lib/plugins" + +pkill $PROCNAME + +${BINDER} --name="${PROCNAME}" \ + --port="${PORT}" \ + --roothttp=. \ + --tracereq=common \ + --token=${TOKEN} \ + --workdir="${TESTPACKAGEDIR}" \ + --binding="../package/lib/afb-signal-composer.so" \ + --binding="$AFBTEST" \ + --call="aft-signal-composer/launch_all_tests:{}" \ + --call="aft-signal-composer/exit:{}" \ + -vvv > ${LOGPIPE} 2>&1 & + +while read -r line +do + [ "$(echo "${line}" | grep 'NOTICE: Browser URL=')" ] && break +done < ${LOGPIPE}
\ No newline at end of file diff --git a/test/afb-test/CMakeLists.txt b/test/afb-test/CMakeLists.txt new file mode 100644 index 0000000..9324aab --- /dev/null +++ b/test/afb-test/CMakeLists.txt @@ -0,0 +1,22 @@ +########################################################################### +# Copyright 2018 IoT.bzh +# +# author: Clément Malléjac <clementmallejac@gmail.com> +# +# 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. +########################################################################### + + +# Include any directory not starting with _ +# ----------------------------------------------------- +PROJECT_SUBDIRS_ADD(${PROJECT_SRC_DIR_PATTERN})
\ No newline at end of file diff --git a/test/afb-test/etc/CMakeLists.txt b/test/afb-test/etc/CMakeLists.txt new file mode 100644 index 0000000..567c186 --- /dev/null +++ b/test/afb-test/etc/CMakeLists.txt @@ -0,0 +1,31 @@ +########################################################################### +# Copyright 2018 IoT.bzh +# +# author: Clément Malléjac <clementmallejac@gmail.com> +# +# 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. +########################################################################### + +################################################## +# Signal-Composer test configuration files +################################################## +PROJECT_TARGET_ADD(afb-test-config) + + file(GLOB CONF_FILES "*.json") + + add_input_files("${CONF_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "TEST-CONFIG" + OUTPUT_NAME ${TARGET_NAME} + )
\ No newline at end of file diff --git a/test/afb-test/etc/aft-signal-composer_config.json b/test/afb-test/etc/aft-signal-composer_config.json new file mode 100644 index 0000000..4ec2285 --- /dev/null +++ b/test/afb-test/etc/aft-signal-composer_config.json @@ -0,0 +1,49 @@ +{ + "id": "http://iot.bzh/download/public/schema/json/ctl-schema.json#", + "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json#", + "metadata": { + "uid": "Test", + "version": "1.0", + "api": "aft-signal-composer", + "info": "AFB-test binding configuration file to test signal-composer api.", + "require": [ + "signal-composer" + ] + }, + "testVerb": { + "uid": "launch_all_tests", + "info": "Launch all the tests", + "action": "lua://AFT#_launch_test", + "args": { + "trace": "signal-composer", + "files": ["signal-composer_BasicAPITest.lua"] + } + }, + "mapis": [{ + "uid": "txc-binding", + "info": "Faked txc-binding API", + "libs": "txc-binding.c", + "verbs": [ + { + "uid": "subscribe", + "info": "Subscribe to signals events", + "action": "plugin://txc-binding#subscribe" + }, + { + "uid": "unsubscribe", + "info": "Unsubscribe previously suscribed signals.", + "action": "plugin://txc-binding#unsubscribe" + }, + { + "uid": "start", + "info": "Start playing trace file.", + "action": "plugin://txc-binding#start" + }, + { + "uid": "stop", + "info": "Start playing trace file.", + "action": "plugin://txc-binding#stop" + } + ] + }] +}
\ No newline at end of file diff --git a/test/afb-test/fixtures/CMakeLists.txt b/test/afb-test/fixtures/CMakeLists.txt new file mode 100644 index 0000000..808ba05 --- /dev/null +++ b/test/afb-test/fixtures/CMakeLists.txt @@ -0,0 +1,33 @@ +########################################################################### +# Copyright 2018 IoT.bzh +# +# author: Clément Malléjac <clementmallejac@gmail.com> +# +# 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. +########################################################################### + + +################################################## +# Signal-Composer Test Fixtures +################################################## +PROJECT_TARGET_ADD(data-files) + + file(GLOB DATA_FILES "*.json") + add_input_files("${DATA_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "TEST-DATA" + OUTPUT_NAME ${TARGET_NAME} + ) + +PROJECT_SUBDIRS_ADD(${PROJECT_SRC_DIR_PATTERN})
\ No newline at end of file diff --git a/conf.d/project/data/localwithgps.json b/test/afb-test/fixtures/localwithgps.json index 4e57404..4e57404 100644 --- a/conf.d/project/data/localwithgps.json +++ b/test/afb-test/fixtures/localwithgps.json diff --git a/conf.d/project/data/nyc-downtown-crosstown.json b/test/afb-test/fixtures/nyc-downtown-crosstown.json index 379c229..379c229 100644 --- a/conf.d/project/data/nyc-downtown-crosstown.json +++ b/test/afb-test/fixtures/nyc-downtown-crosstown.json diff --git a/conf.d/project/data/nyc-uptown-west.json b/test/afb-test/fixtures/nyc-uptown-west.json index fb6f3ee..fb6f3ee 100644 --- a/conf.d/project/data/nyc-uptown-west.json +++ b/test/afb-test/fixtures/nyc-uptown-west.json diff --git a/test/afb-test/fixtures/sig_incomplete.json b/test/afb-test/fixtures/sig_incomplete.json new file mode 100644 index 0000000..8949096 --- /dev/null +++ b/test/afb-test/fixtures/sig_incomplete.json @@ -0,0 +1,19 @@ +{ + "signals": [ + { + "event": "txc/vehicle_speed", + "retention": 30, + "unit": "km/h", + "getSignalsArgs": { + "event": "vehicle_speed" + }, + "onReceived": { + "action": "lua://convert#_Unit_Converter", + "args": { + "from": "km/h", + "to": "mi/h" + } + } + } + ] +}
\ No newline at end of file diff --git a/test/afb-test/fixtures/sig_test.json b/test/afb-test/fixtures/sig_test.json new file mode 100644 index 0000000..f430d8c --- /dev/null +++ b/test/afb-test/fixtures/sig_test.json @@ -0,0 +1,29 @@ +{ + "signals": [ + { + "uid": "vehicle_speedTest1", + "event": "txc/vehicle_speed", + "retention": 30, + "unit": "km/h", + "getSignalsArgs": { + "event": "vehicle_speed" + }, + "onReceived": { + "action": "lua://convert#_Unit_Converter", + "args": { + "from": "km/h", + "to": "mi/h" + } + } + }, + { + "uid": "engine_speedTest2", + "event": "txc/engine_speed", + "retention": 30, + "unit": "rpm", + "getSignalsArgs": { + "event": "engine_speed" + } + } + ] +}
\ No newline at end of file diff --git a/test/afb-test/fixtures/sig_testInvalid.json b/test/afb-test/fixtures/sig_testInvalid.json new file mode 100644 index 0000000..39e92c9 --- /dev/null +++ b/test/afb-test/fixtures/sig_testInvalid.json @@ -0,0 +1,20 @@ +{ + "signals": [ + { + "uid": "invalidSignal", + "event": "txc/invalidSignal", + "retention": -1, + "unit": "invalidSignal", + "getSignalsArgs": { + "event": "invalidSignal" + }, + "onReceived": { + "action": "lua://convert#_Unit_Converter", + "args": { + "from": "km/h", + "to": "mi/h" + } + } + } + ] +}
\ No newline at end of file diff --git a/test/afb-test/fixtures/txc-binding/CMakeLists.txt b/test/afb-test/fixtures/txc-binding/CMakeLists.txt new file mode 100644 index 0000000..76a4923 --- /dev/null +++ b/test/afb-test/fixtures/txc-binding/CMakeLists.txt @@ -0,0 +1,38 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll <fulup@iot.bzh> +# contrib: 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. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(txc-binding) + + # Define project Targets + add_library(${TARGET_NAME} MODULE txc-binding.c) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + SUFFIX ".ctlso" + PREFIX "" + LABELS "TEST-PLUGIN" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + ctl-utilities + ${link_libraries})
\ No newline at end of file diff --git a/test/afb-test/fixtures/txc-binding/txc-binding.c b/test/afb-test/fixtures/txc-binding/txc-binding.c new file mode 100644 index 0000000..c9a5a68 --- /dev/null +++ b/test/afb-test/fixtures/txc-binding/txc-binding.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author José Bollo <jose.bollo@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. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <math.h> +#include <pthread.h> +#include <fcntl.h> + +#include <json-c/json.h> + +#include <afb/afb-binding.h> +#include <ctl-config.h> + + +CTLP_LUA_REGISTER("txc-binding"); + +struct signal { + const char *name; + struct afb_event event; +}; + +static int playing; +static int stoping; + +static struct signal signals[] = { + { .name = "START" }, + { .name = "STOP" }, + { .name = "accelerator_pedal_position" }, + { .name = "brake_pedal_status" }, + { .name = "button_event" }, + { .name = "door_status" }, + { .name = "engine_speed" }, + { .name = "fuel_consumed_since_restart" }, + { .name = "fuel_level" }, + { .name = "headlamp_status" }, + { .name = "high_beam_status" }, + { .name = "ignition_status" }, + { .name = "latitude" }, + { .name = "longitude" }, + { .name = "odometer" }, + { .name = "parking_brake_status" }, + { .name = "steering_wheel_angle" }, + { .name = "torque_at_transmission" }, + { .name = "transmission_gear_position" }, + { .name = "vehicle_speed" }, + { .name = "windshield_wiper_status" } +}; + +static struct signal *getsig(const char *name) +{ + int low, hig, mid, cmp; + + low = 0; + hig = sizeof signals / sizeof * signals; + while (low < hig) { + mid = (low + hig) >> 1; + cmp = strcmp(signals[mid].name, name); + if (cmp == 0) { + return &signals[mid]; + } else { + if (cmp > 0) + hig = mid; + else + low = mid + 1; + } + } + return NULL; +} + + +static void send_trace(const char *name, struct json_object *object) +{ + struct signal *sig = getsig(name); + + if (sig && afb_event_is_valid(sig->event)) { + afb_event_push(sig->event, json_object_get(object)); + } +} + +static void *play_traces(void *opaque) +{ + int len, fd; + struct json_object *args = opaque; + struct json_tokener *tokener = NULL; + struct json_object *object; + char line[1024]; + FILE *file = NULL; + const char *info; + double speed = 1.0; + int started = 0; + long double init = 0.0; + long double prev = 0.0; + long double base = 0.0; + long double t, i, f; + struct json_object *ots; + struct json_object *on; + int hasots; + int hason; + struct timespec ts; + + /* creates the tokener */ + tokener = json_tokener_new(); + if (tokener == NULL) { + info = "can't allocate tokener"; + goto end; + } + + /* get the speed */ + if (json_object_object_get_ex(args, "speed", &object)) { + speed = json_object_get_double(object); + speed = speed <= 0 ? 1.0 : 1.0 / speed; + } + + /* open the file */ + if (!json_object_object_get_ex(args, "filename", &object)) { + info = "can't find filename"; + goto end; + } + fd = afb_daemon_rootdir_open_locale(json_object_get_string(object), O_RDONLY, NULL); + if (fd < 0) { + info = "can't open the file"; + goto end; + } + file = fdopen(fd, "r"); + if (file == NULL) { + close(fd); + info = "can't instanciate the file"; + goto end; + } + + /* send the start signal */ + send_trace("START", NULL); + + /* reads the file and send its content */ + while(!stoping && fgets(line, (int)sizeof line, file)) { + len = (int)strlen(line); + if (len && line[len-1] == '\n') + len--; + if (len) { + json_tokener_reset(tokener); + object = json_tokener_parse_ex(tokener, line, len); + /* silently ignore errors ?!! */ + if (object != NULL) { + hason = json_object_object_get_ex(object, "name", &on); + hasots = json_object_object_get_ex(object, "timestamp", &ots); + if (hasots && hason) { + if (started) { + t = speed * (json_object_get_double(ots) - init); + clock_gettime(CLOCK_REALTIME, &ts); + } + else { + init = json_object_get_double(ots); + started = 1; + clock_gettime(CLOCK_REALTIME, &ts); + base = (long double)ts.tv_sec + ((long double)ts.tv_nsec / 1000000000.0); + t = 0; + } + + if (t > prev) { + f = modfl(base + t, &i); + ts.tv_sec = (time_t)i; + ts.tv_nsec = (long)(1000000000.0 * f); + prev = t; + clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL); + } + + t = t + (long double)ts.tv_sec + ((long double)ts.tv_nsec / 1000000000.0); + json_object_object_add(object, "timestamp", json_object_new_double(t)); + + send_trace(json_object_get_string(on), object); + } + else { + json_object_put(object); + } + } + } + } + info = NULL; + +end: + /* send the stop signal */ + send_trace("STOP", NULL); + + /* cleanup */ + if (file) + fclose(file); + if (tokener) + json_tokener_free(tokener); + json_object_put(args); + + /* terminate */ + stoping = 0; + playing = 0; + return NULL; +} + + +CTLP_CAPI (start, source, argsJ, eventJ) +{ + struct json_object *args, *a; + int fd; + pthread_t tid; + + /* check filename argument */ + args = afb_req_json(source->request); + if (!json_object_object_get_ex(args, "filename", &a)) { + afb_req_fail(source->request, "error", "argument 'filename' is missing"); + return -1; + } + fd = afb_daemon_rootdir_open_locale(json_object_get_string(a), O_RDONLY, NULL); + if (fd < 0) { + afb_req_fail(source->request, "error", "argument 'filename' is not a readable file"); + return -1; + } + close(fd); + + /* check speed argument */ + if (json_object_object_get_ex(args, "speed", &a)) { + if (json_object_get_double(a) <= 0) { + afb_req_fail(source->request, "error", "argument 'speed' is not a valid positive number"); + return -1; + } + } + + /* check the state */ + if (playing) { + afb_req_fail(source->request, "error", "already playing"); + return -1; + } + + /* valid then try to start */ + playing = 1; + stoping = 0; + if (pthread_create(&tid, NULL, play_traces, json_object_get(args)) != 0) { + playing = 0; + afb_req_fail(source->request, "error", "can't start to play"); + return -1; + } + + afb_req_success(source->request, NULL, NULL); + return 0; + +} + +CTLP_CAPI (stop, source, argsJ, eventJ) +{ + if (playing) + stoping = 1; + afb_req_success(source->request, NULL, NULL); + return 0; +} + +static int subscribe_unsubscribe_sig(struct afb_req request, int subscribe, struct signal *sig) +{ + if (!afb_event_is_valid(sig->event)) { + if (!subscribe) + return 1; + sig->event = afb_daemon_make_event(sig->name); + if (!afb_event_is_valid(sig->event)) { + return 0; + } + } + + if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, sig->event)) < 0) { + return 0; + } + + return 1; +} + +static int subscribe_unsubscribe_all(struct afb_req request, int subscribe) +{ + int i, n, e; + + n = sizeof signals / sizeof * signals; + e = 0; + for (i = 0 ; i < n ; i++) + e += !subscribe_unsubscribe_sig(request, subscribe, &signals[i]); + return e == 0; +} + +static int subscribe_unsubscribe_name(struct afb_req request, int subscribe, const char *name) +{ + struct signal *sig; + + if (0 == strcmp(name, "*")) + return subscribe_unsubscribe_all(request, subscribe); + + sig = getsig(name); + if (sig == NULL) { + return 0; + } + + return subscribe_unsubscribe_sig(request, subscribe, sig); +} + +static void subscribe_unsubscribe(struct afb_req request, int subscribe) +{ + int ok, i; + size_t n; + struct json_object *args, *a, *x; + + /* makes the subscription/unsubscription */ + args = afb_req_json(request); + if (args == NULL || !json_object_object_get_ex(args, "event", &a)) { + ok = subscribe_unsubscribe_all(request, subscribe); + } else if (json_object_get_type(a) != json_type_array) { + ok = subscribe_unsubscribe_name(request, subscribe, json_object_get_string(a)); + } else { + n = json_object_array_length(a); + ok = 0; + for (i = 0 ; i < n ; i++) { + x = json_object_array_get_idx(a, i); + if (subscribe_unsubscribe_name(request, subscribe, json_object_get_string(x))) + ok++; + } + ok = (ok == n); + } + + /* send the report */ + if (ok) + afb_req_success(request, NULL, NULL); + + else + afb_req_fail(request, "error", NULL); + +} + +CTLP_CAPI (subscribe, source, argsJ, eventJ){ + subscribe_unsubscribe(source->request, 1); + return 0; +} + +CTLP_CAPI (unsubscribe, source, argsJ, eventJ){ + subscribe_unsubscribe(source->request, 0); + return 0; +}
\ No newline at end of file diff --git a/test/afb-test/tests/CMakeLists.txt b/test/afb-test/tests/CMakeLists.txt new file mode 100644 index 0000000..719b3d8 --- /dev/null +++ b/test/afb-test/tests/CMakeLists.txt @@ -0,0 +1,31 @@ +########################################################################### +# Copyright 2018 IoT.bzh +# +# author: Clément Malléjac <clementmallejac@gmail.com> +# +# 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. +########################################################################### + + +################################################## +# Signal-Composer Lua Scripts +################################################## +PROJECT_TARGET_ADD(test-files) + + file(GLOB LUA_FILES "*.lua" "*.sh") + add_input_files("${LUA_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "TEST-DATA" + OUTPUT_NAME ${TARGET_NAME} + )
\ No newline at end of file diff --git a/test/afb-test/tests/signal-composer_BasicAPITest.lua b/test/afb-test/tests/signal-composer_BasicAPITest.lua new file mode 100644 index 0000000..8e9e212 --- /dev/null +++ b/test/afb-test/tests/signal-composer_BasicAPITest.lua @@ -0,0 +1,184 @@ +--[[ + Copyright (C) 2018 "IoT.bzh" + Author Clément Malléjac <clementmallejac@gmail.com> + + 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 testPrefix ="signal_composer_BasicAPITest_"; + +-- This tests the 'list' verb of the signal-composer API +_AFT.testVerbStatusSuccess(testPrefix.."list","signal-composer","list", {}); + + +-- This tests the 'subscribe' verb of the signal-composer API +_AFT.testVerbStatusSuccess(testPrefix.."subscribe","signal-composer","subscribe",{ signal = "longitude"},nil, + function() + _AFT.callVerb("signal-composer","unsubscribe",{ signal = "longitude"}) + end); + + +-- This tests the 'unsubscribe' verb of the signal-composer API +_AFT.testVerbStatusSuccess(testPrefix.."unsubscribe","signal-composer","unsubscribe",{ signal = "heading"}, + function() + _AFT.callVerb("signal-composer","subscribe",{ signal = "heading"}) + end, nil); + +-- This tests the 'unsubscribe' verb of the signal-composer API when we are not actually subscribed to a signal +_AFT.testVerbStatusSuccess(testPrefix.."doubleUnsubscribe","signal-composer","unsubscribe",{ signal = "latitude"}, + function() + _AFT.callVerb("signal-composer","unsubscribe",{ signal = "latitude"}) + end,nil); + +-- This tests the 'unsubscribe' verb of the signal-composer API when unsubscribing from a non-existing signal +_AFT.testVerbStatusSuccess(testPrefix.."unsubscribeNonExistingSignal","signal-composer","unsubscribe",{ signal = "notASignal"}); + +-- This tests the 'get' verb of the signal-composer API, without any options, this should return the last value for that signal +_AFT.testVerbStatusSuccess(testPrefix.."getNoFilter","signal-composer","get",{signal= "fuel_level"}); + +-- This tests the 'get' verb of the signal-composer API, with the 'average' option, this should return the average value over the last X seconds +_AFT.testVerbStatusSuccess(testPrefix.."getFilterAvg","signal-composer","get",{signal= "odometer", options= {average= 10}}); + +-- This tests the 'get' verb of the signal-composer API, with the 'minimum' option, this should return the minimum value over the last X seconds +_AFT.testVerbStatusSuccess(testPrefix.."getFilterMin","signal-composer","get",{signal= "latitude", options= {minimum= 10}}); + +-- This tests the 'get' verb of the signal-composer API, with the 'maximum' option, this should return the maximum value over the last X seconds +_AFT.testVerbStatusSuccess(testPrefix.."getFilterMax","signal-composer","get",{signal= "vehicle_speed", options= {maximum= 10}}); + +--[[ This tests the 'addObjects' verb of the signal-composer API, this is by passing the path of a json containing signals + then making a get, a subscribe, and an unsubscribe looking for any misbehaviour from signals added with the verb ]] +_AFT.describe(testPrefix.."addObjectsByFile",function() + _AFT.assertVerbStatusSuccess("signal-composer","addObjects",{file = _AFT.bindingRootDir.."var/sig_test.json"}) + _AFT.assertVerbStatusSuccess("signal-composer","get",{signal= "vehicle_speedTest1",options= {average=10}}); + _AFT.assertVerbStatusSuccess("signal-composer","subscribe",{ signal = "vehicle_speedTest1"}); + _AFT.assertVerbStatusSuccess("signal-composer","unsubscribe",{ signal = "vehicle_speedTest1"}); +end); + +_AFT.setAfter(testPrefix.."addObjectsByFile",function() + _AFT.callVerb("signal-composer","unsubscribe",{ signal = "vehicle_speedTest1"}) +end) + + + +-- This tests the 'addObjects' verb of the signal-composer API, this is by passing directly the json object as a lua table +_AFT.testVerbStatusSuccess(testPrefix.."addObjectsDirect","signal-composer","addObjects", +{ + signals= { + { + uid= "vehicle_speedTest3", + event= "txc/vehicle_speed", + retention= 30, + unit= "km/h", + getSignalsArgs= { + event= "vehicle_speed" + }, + onReceived= { + action= "lua://convert#_Unit_Converter", + args= { + from= "km/h", + to= "mi/h" + } + } + }, + { + uid= "engine_speedTest4", + event= "txc/engine_speed", + retention= 30, + unit= "rpm", + getSignalsArgs= { + event= "engine_speed" + } + } + } +} +); + +--[[ This tests the 'addObjects' verb of the signal-composer API, this is by passing directly the json object as a lua table. + This one has invalid values for most of its field, the binding should not be able to add it ]] +_AFT.testVerbStatusError(testPrefix.."addObjectsDirect_InvalidSignal","signal-composer","addObjects", +{ + signals= { + { + uid= "invalidSignal", + event= "txc/invalidSignal", + retention= -1, + unit= "invalidSignal", + getSignalsArgs= { + event= "invalidSignal" + }, + onReceived= { + action= "lua://convert#_Unit_Converter", + args= { + from= "km/h", + to= "mi/h" + } + } + } + } +} +); + +--[[ This tests the 'addObjects' verb of the signal-composer API, this is by passing directly the json object as a lua table. + This one is missing the mandatory 'uid' field, the binding should not be able to add it ]] +_AFT.testVerbStatusError(testPrefix.."addObjectsDirect_MissingField","signal-composer","addObjects", +{ + signals= { + { + event= "txc/invalidSignal2", + retention= 30, + unit= "km/h", + getSignalsArgs= { + event= "vehicle_speed" + }, + onReceived= { + action= "lua://convert#_Unit_Converter", + args= { + from= "km/h", + to= "mi/h" + } + } + } + } +} +); + +--[[ This tests the 'addObjects' verb of the signal-composer API, this is by passing the path of a json containing signals + This one has invalid values for most of its field, the binding should not be able to add it ]] +_AFT.testVerbStatusError(testPrefix.."addObjectsByFile_InvalidSignal","signal-composer","addObjects",{file = _AFT.bindingRootDir.."var/sig_testInvalid.json"}); + +--[[ This tests the 'addObjects' verb of the signal-composer API, this is by passing the path of a json containing signals + This one is missing the mandatory 'uid' field, the binding should not be able to add it ]] +_AFT.testVerbStatusError(testPrefix.."addObjectsByFile_Missingfield","signal-composer","addObjects",{file = _AFT.bindingRootDir.."var/sig_incomplete.json"}); + +-- This tests the 'subscribe' verb of the signal-composer API, with a non existing signal, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."subscribeNonExistingSignal","signal-composer","subscribe",{ signal = "notASignal"}); + +-- This tests the 'get' verb of the signal-composer API, with an invalid option name, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."getFilterInvalid","signal-composer","get",{signal= "latitude", options= {notValid= 10}}); + +-- This tests the 'get' verb of the signal-composer API, with a non existing signal, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."getNoFilterInvalidSignal","signal-composer","get",{signal= "notAValidSignal"}); + +-- This tests the 'get' verb of the signal-composer API, with an invalid option value, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."getFilterOptionInvalidValue","signal-composer","get",{signal= "odometer", options= {average= -1}}); + +-- This tests the 'get' verb of the signal-composer API, with an invalid parameter name, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."getFilterInvalidFirstArgument","signal-composer","get",{notValidAtAll= "vehicule_speed", options= {average= 10}}); + +-- This tests the 'get' verb of the signal-composer API, with an invalid second parameter name, it should reply with an error +_AFT.testVerbStatusError(testPrefix.."getFilterInvalidSecondArgument","signal-composer","get",{signal= "vehicule_speed", notValidAtAll= {average= 10}}); + +_AFT.exitAtEnd();
\ No newline at end of file |