aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClément Malléjac <clementmallejac@gmail.com>2018-07-27 17:05:53 +0200
committerClément Malléjac <clementmallejac@gmail.com>2018-08-22 11:33:44 +0200
commit7697648397638b082ce3d3d824c8c128490fc7ce (patch)
tree9dd46cf134acabd57f90492b8d2f3be7bd7fe63c
parent92f0e16392712fb80954426722675292d551bf0c (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>
m---------conf.d/app-templates0
-rw-r--r--conf.d/cmake/config.cmake10
-rw-r--r--conf.d/project/data/CMakeLists.txt10
-rw-r--r--test/CMakeLists.txt27
-rwxr-xr-xtest/afb-test.sh41
-rw-r--r--test/afb-test/CMakeLists.txt22
-rw-r--r--test/afb-test/etc/CMakeLists.txt31
-rw-r--r--test/afb-test/etc/aft-signal-composer_config.json49
-rw-r--r--test/afb-test/fixtures/CMakeLists.txt33
-rw-r--r--test/afb-test/fixtures/localwithgps.json (renamed from conf.d/project/data/localwithgps.json)0
-rw-r--r--test/afb-test/fixtures/nyc-downtown-crosstown.json (renamed from conf.d/project/data/nyc-downtown-crosstown.json)0
-rw-r--r--test/afb-test/fixtures/nyc-uptown-west.json (renamed from conf.d/project/data/nyc-uptown-west.json)0
-rw-r--r--test/afb-test/fixtures/sig_incomplete.json19
-rw-r--r--test/afb-test/fixtures/sig_test.json29
-rw-r--r--test/afb-test/fixtures/sig_testInvalid.json20
-rw-r--r--test/afb-test/fixtures/txc-binding/CMakeLists.txt38
-rw-r--r--test/afb-test/fixtures/txc-binding/txc-binding.c356
-rw-r--r--test/afb-test/tests/CMakeLists.txt31
-rw-r--r--test/afb-test/tests/signal-composer_BasicAPITest.lua184
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