aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStoyan Bogdanov <stoyan.bogdanov@konsulko.com>2019-06-12 16:12:39 +0300
committerStoyan Bogdanov <stoyan.bogdanov@konsulko.com>2019-06-18 11:41:45 +0300
commit089807fbbc4429ede68ef4fa846367345259de36 (patch)
treeada004340671ac5ee9b9b609ac646c637e8f3e98
parent7eba64b591678e8e150ca5da0ea3537c3dd4db1f (diff)
tests: network: Add test bindings for agl-service-network
- Remove agl-service-network-ctl.c from tests folder. - Create the file and folders structure required. for building test bindings. Add all required Cmake files. - Create aft-agl-network.json configuration file for testing binding. - Create network.lua for testing bindings. Bug-AGL: SPEC-2515 Signed-off-by: Stoyan Bogdanov <stoyan.bogdanov@konsulko.com> Change-Id: I9df72a2d9d03189d3917c6e84f633af7603436b0
-rw-r--r--test/CMakeLists.txt38
-rw-r--r--test/TEST-README.md30
-rw-r--r--test/afb-test/CMakeLists.txt21
-rw-r--r--test/afb-test/etc/CMakeLists.txt32
-rw-r--r--test/afb-test/etc/aft-agl-network.json22
-rw-r--r--test/afb-test/tests/CMakeLists.txt31
-rw-r--r--test/afb-test/tests/network.lua52
-rw-r--r--test/agl-service-network-ctl.c872
8 files changed, 213 insertions, 885 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 79065a4..2499cba 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,16 +1,28 @@
-###########################################
-# build and install afb-client-demo
-###########################################
-PKG_CHECK_MODULES(libsystemd libsystemd>=222)
-PKG_CHECK_MODULES(libafbwsc libafbwsc>=5.99)
+###########################################################################
+# Copyright 2019 Konsulko Group
+#
+# Author: Stoyan Bogdanov <stoyan.bogdanov@konsulko.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.
+###########################################################################
-ADD_EXECUTABLE(agl-service-network-ctl agl-service-network-ctl.c)
-TARGET_LINK_LIBRARIES(agl-service-network-ctl
- ${link_libraries}
- ${libsystemd_LDFLAGS}
- ${libafbwsc_LDFLAGS}
-)
-INSTALL(TARGETS agl-service-network-ctl
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+# Include any directory not starting with _
+# -----------------------------------------------------
+PROJECT_SUBDIRS_ADD(${PROJECT_SRC_DIR_PATTERN})
+
+ADD_TEST(NAME AGL_SERVICE_GPS_TESTS
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND afb-test.sh "${CMAKE_BINARY_DIR}/package" "${CMAKE_BINARY_DIR}/package-test" SERVICE
+ )
diff --git a/test/TEST-README.md b/test/TEST-README.md
new file mode 100644
index 0000000..b2475ae
--- /dev/null
+++ b/test/TEST-README.md
@@ -0,0 +1,30 @@
+## Building the test widgets
+1. Source the SDK environment script
+2. Create a build directory
+3. Configure and build the project
+
+```
+mkdir build
+cd build
+cmake .. -DBUILD_TEST_WGT=TRUE
+make
+make widget
+
+```
+Note: If you omit the -DBUILD_TEST_WGT=TRUE parameter for cmake,
+you'll have to type `make test_widget` to compile the test widget.
+
+This should produce two _.wgt_ files - one with the service
+and one with the tests within the build directory.
+
+Run the tests:
+```
+scp *.wgt root@<board-ip>:~
+ssh root@<board-ip>
+afm-test $(ls *test.wgt)
+
+```
+
+network.lua is testing just part of the verbs presented in the agl-service-network.
+Proper testing of wifi, bluetooth and ethernet require known enviroment,
+this is the reason why some of the vers are not tested.
diff --git a/test/afb-test/CMakeLists.txt b/test/afb-test/CMakeLists.txt
new file mode 100644
index 0000000..44bfeac
--- /dev/null
+++ b/test/afb-test/CMakeLists.txt
@@ -0,0 +1,21 @@
+###########################################################################
+# Copyright 2019 Konsulko Group
+#
+# Author: Stoyan Bogdanov <stoyan.bogdanov@konsulko.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})
diff --git a/test/afb-test/etc/CMakeLists.txt b/test/afb-test/etc/CMakeLists.txt
new file mode 100644
index 0000000..eb0fdb8
--- /dev/null
+++ b/test/afb-test/etc/CMakeLists.txt
@@ -0,0 +1,32 @@
+###########################################################################
+# Copyright 2019 Konsulko Group
+#
+# Author: Stoyan Bogdanov <stoyan.bogdanov@konsulko.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.
+###########################################################################
+
+##################################################
+# network 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}
+ )
+
diff --git a/test/afb-test/etc/aft-agl-network.json b/test/afb-test/etc/aft-agl-network.json
new file mode 100644
index 0000000..495249a
--- /dev/null
+++ b/test/afb-test/etc/aft-agl-network.json
@@ -0,0 +1,22 @@
+{
+ "id": "http://iot.bzh/download/public/schema/json/ctl-schema.json#",
+ "": "http://iot.bzh/download/public/schema/json/ctl-schema.json#",
+ "metadata": {
+ "uid": "Test",
+ "version": "1.0",
+ "api": "aft-network",
+ "info": "AFB-test binding configuration file to test network api.",
+ "require": [
+ "network-manager"
+ ]
+ },
+ "testVerb": {
+ "uid": "launch_all_tests",
+ "info": "Launch all the tests",
+ "action": "lua://AFT#_launch_test",
+ "args": {
+ "trace": "network",
+ "files": ["network.lua"]
+ }
+ }
+}
diff --git a/test/afb-test/tests/CMakeLists.txt b/test/afb-test/tests/CMakeLists.txt
new file mode 100644
index 0000000..b867d34
--- /dev/null
+++ b/test/afb-test/tests/CMakeLists.txt
@@ -0,0 +1,31 @@
+###########################################################################
+# Copyright 2019 Konsulko Group
+#
+# Author: Stoyan Bogdanov <stoyan.bogdanov@konsulko.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.
+###########################################################################
+
+##################################################
+# network 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}
+ )
+
diff --git a/test/afb-test/tests/network.lua b/test/afb-test/tests/network.lua
new file mode 100644
index 0000000..2aebe23
--- /dev/null
+++ b/test/afb-test/tests/network.lua
@@ -0,0 +1,52 @@
+--[[
+ Copyright 2019 Konsulko Group
+
+ author:Stoyan Bogdanov <stoyan.bogdanov@konsulko.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.
+--]]
+
+
+-- Test subscribe [working ok]
+_AFT.testVerbStatusSuccess('testSubscribeASuccess','network-manager','subscribe', {value="global_state"})
+_AFT.testVerbStatusSuccess('testSubscribeBSuccess','network-manager','subscribe', {value="technologies"})
+_AFT.testVerbStatusSuccess('testSubscribeCSuccess','network-manager','subscribe', {value="technology_properties"})
+_AFT.testVerbStatusSuccess('testSubscribeDSuccess','network-manager','subscribe', {value="services"})
+_AFT.testVerbStatusSuccess('testSubscribeESuccess','network-manager','subscribe', {value="service_properties"})
+_AFT.testVerbStatusSuccess('testSubscribeFSuccess','network-manager','subscribe', {value="agent"})
+
+-- Test unsubscribe
+_AFT.testVerbStatusSuccess('testUnsubscribeASuccess','network-manager','unsubscribe', {value="global_state"})
+_AFT.testVerbStatusSuccess('testUnsubscribeBSuccess','network-manager','unsubscribe', {value="technologies"})
+_AFT.testVerbStatusSuccess('testUnsubscribeCSuccess','network-manager','unsubscribe', {value="technology_properties"})
+_AFT.testVerbStatusSuccess('testUnsubscribeDSuccess','network-manager','unsubscribe', {value="services"})
+_AFT.testVerbStatusSuccess('testUnsubscribeESuccess','network-manager','unsubscribe', {value="service_properties"})
+_AFT.testVerbStatusSuccess('testUnsubscribeFSuccess','network-manager','unsubscribe', {value="agent"})
+
+_AFT.testVerbStatusSuccess('testStateSuccess','network-manager','state', {})
+_AFT.testVerbStatusSuccess('testOfflineSuccess','network-manager','offline', {})
+_AFT.testVerbStatusSuccess('testTechnologiesSuccess','network-manager','technologies', {})
+_AFT.testVerbStatusSuccess('testServicesSuccess','network-manager','services', {})
+
+_AFT.testVerbStatusSuccess('testDisableTechnologySuccess','network-manager','disable_technology', {technology="ethernet"})
+_AFT.testVerbStatusSuccess('testEnableTechnologySuccess','network-manager', 'enable_technology', {technology="ethernet"})
+
+_AFT.testVerbStatusSuccess('testDisableTechnologySuccess','network-manager','disable_technology', {technology="wifi"})
+_AFT.testVerbStatusSuccess('testEnableTechnologySuccess','network-manager', 'enable_technology', {technology="wifi"})
+
+_AFT.testVerbStatusSuccess('testDisableTechnologySuccess','network-manager','disable_technology', {technology="bluetooth"})
+_AFT.testVerbStatusSuccess('testEnableTechnologySuccess','network-manager', 'enable_technology', {technology="bluetooth"})
+
+_AFT.testVerbStatusSuccess('testgetpropertySuccess','network-manager','get_property', {technology="wifi"})
+_AFT.testVerbStatusSuccess('testgetpropertySuccess','network-manager','get_property', {technology="ethernet"})
+_AFT.testVerbStatusSuccess('testgetpropertySuccess','network-manager','get_property', {technology="bluetooth"})
diff --git a/test/agl-service-network-ctl.c b/test/agl-service-network-ctl.c
deleted file mode 100644
index 6808b8d..0000000
--- a/test/agl-service-network-ctl.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright (C) 2018 Konsulko Group
- * Author Pantelis Antoniou <pantelis.antoniou@konsulko.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.
- */
-
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <pthread.h>
-#include <ctype.h>
-#include <alloca.h>
-#include <assert.h>
-
-#include <systemd/sd-event.h>
-#include <json-c/json.h>
-
-#include <afb/afb-wsj1.h>
-#include <afb/afb-ws-client.h>
-#include <afb/afb-proto-ws.h>
-
-struct state {
- const char *url;
- int port;
- const char *token;
- const char *api;
- char *uri;
- bool interactive;
- bool debug;
- bool noexit;
-
- sd_event *loop;
- struct afb_wsj1 *wsj1;
- const char *proto;
- bool hangup;
-};
-
-struct cmd {
- const char *verb;
- int (*call)(struct state *s, const struct cmd *c, int argc, char *argv[]);
- void (*reply)(void *closure, struct afb_wsj1_msg *msg);
-};
-
-/* print usage of the program */
-/* declaration of functions */
-static void on_wsj1_hangup(void *closure, struct afb_wsj1 *wsj1);
-static void on_wsj1_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg);
-static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg);
-
-/* the callback interface for wsj1 */
-static struct afb_wsj1_itf wsj1_itf = {
- .on_hangup = on_wsj1_hangup,
- .on_call = on_wsj1_call,
- .on_event = on_wsj1_event
-};
-
-static void on_reply(struct state *s, const char *verb, struct afb_wsj1_msg *msg)
-{
- printf("ON-REPLY %s: %s: %s\n%s\n",
- s->api,
- verb,
- afb_wsj1_msg_is_reply_ok(msg) ? "OK" : "ERROR",
- json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
- JSON_C_TO_STRING_PRETTY));
- fflush(stdout);
-
- /* if non interactive terminate */
- if (!s->interactive) {
- if (!s->noexit)
- sd_event_exit(s->loop,
- afb_wsj1_msg_is_reply_ok(msg) ? 0 : EXIT_FAILURE);
- else
- printf("Ctrl-C to exit\n");
- }
-
-}
-
-static int do_call(struct state *s, const struct cmd *c, json_object *jparams)
-{
- printf("CALL %s(%s)\n", c->verb,
- jparams ? json_object_to_json_string(jparams) : "");
-
- return afb_wsj1_call_j(s->wsj1, s->api, c->verb, jparams, c->reply, s);
-}
-
-static int call_void(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- return do_call(s, c, NULL);
-}
-
-static void on_ping_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "ping", msg);
-}
-
-static void on_subscribe_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "subscribe", msg);
-}
-
-static void on_unsubscribe_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "unsubscribe", msg);
-}
-
-static int call_subscribe_unsubscribe(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj;
-
- /* must give event name */
- if (argc < 1)
- return -1;
- jobj = json_object_new_object();
- json_object_object_add(jobj, "value", json_object_new_string(argv[0]));
-
- return do_call(s, c, jobj);
-}
-
-static void on_state_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "state", msg);
-}
-
-static void on_technologies_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "technologies", msg);
-}
-
-static void on_services_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "services", msg);
-}
-
-static void on_enable_technology_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "enable_technology", msg);
-}
-
-static void on_disable_technology_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "disable_technology", msg);
-}
-
-static int call_technology_arg(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj;
-
- if (argc < 1)
- return -1;
-
- jobj = json_object_new_object();
- json_object_object_add(jobj, "technology", json_object_new_string(argv[0]));
-
- return do_call(s, c, jobj);
-}
-
-static void on_scan_services_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "scan_services", msg);
-}
-
-static void on_offline_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "offline", msg);
-}
-
-static int call_offline(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj;
-
- /* with no arguments it's a getter */
- if (argc >= 1) {
- jobj = json_object_new_object();
- json_object_object_add(jobj, "value", json_object_new_string(argv[0]));
- } else
- jobj = NULL;
-
- return do_call(s, c, jobj);
-}
-
-static void on_connect_service_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "connect_service", msg);
-}
-
-static int call_service_arg(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj;
-
- if (argc < 1)
- return -1;
-
- jobj = json_object_new_object();
- json_object_object_add(jobj, "service", json_object_new_string(argv[0]));
-
- return do_call(s, c, jobj);
-}
-
-static void on_disconnect_service_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "disconnect_service", msg);
-}
-
-static void on_remove_service_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "remove_service", msg);
-}
-
-static void on_move_service_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "move_service", msg);
-}
-
-static int call_move_service(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj;
-
- /* 3 arguments and the middle must be before or after */
- if (argc < 3 || (strcmp(argv[1], "before") && strcmp(argv[1], "after")))
- return -1;
-
- jobj = json_object_new_object();
- json_object_object_add(jobj, "service", json_object_new_string(argv[0]));
- json_object_object_add(jobj,
- !strcmp(argv[1], "before") ? "before_service" : "after_service",
- json_object_new_string(argv[2]));
-
- return do_call(s, c, jobj);
-}
-
-static void on_set_property_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "set_property", msg);
-}
-
-static void on_get_property_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "get_property", msg);
-}
-
-static bool get_property_obj(json_object *jparent, int argc, char *argv[])
-{
- json_object *jobj, *jobj2;
- int i, j, nest;
-
- for (i = 0; i < argc; i++) {
-
- if ((i < (argc - 1) && !strcmp(argv[i+1], "{"))) {
- nest = 1;
- for (j = i + 2; j < argc; j++) {
- if (!strcmp(argv[j], "{"))
- nest++;
- else if (!strcmp(argv[j], "}"))
- nest--;
-
- if (!nest)
- break;
- }
- if (j >= argc)
- return false;
-
- jobj = json_object_new_object();
-
- jobj2 = json_object_new_array();
- get_property_obj(jobj2, j - i - 2, argv + i + 2);
- json_object_object_add(jobj, argv[i], jobj2);
- i = j;
- } else
- jobj = json_object_new_string(argv[i]);
-
- json_object_array_add(jparent, jobj);
-
- }
-
- return true;
-}
-
-struct json_object *get_property_value(const char *str)
-{
- char *le, *de;
- long long ll;
- double d;
-
- if (!strcmp(str, "null"))
- return NULL;
- if (!strcmp(str, "true"))
- return json_object_new_boolean(true);
- if (!strcmp(str, "false"))
- return json_object_new_boolean(false);
-
- /* try both double and long and see which one is furthest */
- ll = strtoll(str, &le, 0);
- d = strtod(str, &de);
-
- if (de > le) {
- while (isspace(*de))
- de++;
- if (!*de)
- return json_object_new_double(d);
- } else {
- while (isspace(*le))
- le++;
- if (!*le)
- return json_object_new_int64((int64_t)ll);
- }
-
- /* everything else is a string */
- return json_object_new_string(str);
-}
-
-/* how many args is a single json object value */
-static int next_span(int pos, int argc, char *argv[])
-{
- const char *left, *right;
- int j, nest;
-
- if (pos >= argc)
- return 0;
-
- if (!strcmp(argv[pos], "{") || !strcmp(argv[pos], "[")) {
-
- if (!strcmp(argv[pos], "{")) {
- left = "{";
- right = "}";
- } else {
- left = "[";
- right = "]";
- }
- nest = 1;
- for (j = pos + 1; nest > 0 && j < argc; j++) {
- if (!strcmp(argv[j], left))
- nest++;
- else if (!strcmp(argv[j], right))
- nest--;
- }
- if (nest && j >= argc) {
- fprintf(stderr, "nesting error\n");
- return -1;
- }
-
- return j - pos;
- }
- return 1;
-}
-
-bool add_property_value(json_object *jparent, const char *key, int argc, char *argv[])
-{
- json_object *jobj;
- const char *key2;
- int i, span;
-
- if (!strcmp(argv[0], "[")) {
- assert(!strcmp(argv[argc - 1], "]"));
-
- argc -= 2;
- argv++;
-
- jobj = json_object_new_array();
-
- for (i = 0; i < argc; ) {
- span = next_span(i, argc, argv);
- if (span < 0) {
- fprintf(stderr, "bad nesting\n");
- return NULL;
- }
-
- if (!add_property_value(jobj, NULL, span, argv + i)) {
- fprintf(stderr, "error adding array\n");
- return false;
- }
- i += span;
-
- }
- } else if (!strcmp(argv[0], "{")) {
- assert(!strcmp(argv[argc - 1], "}"));
-
- argc -= 2;
- argv++;
-
- jobj = json_object_new_object();
-
- for (i = 0; i < argc; ) {
- key2 = argv[i];
-
- span = next_span(i + 1, argc, argv);
- if (span < 0) {
- fprintf(stderr, "bad nesting\n");
- return NULL;
- }
-
- if (!add_property_value(jobj, key2, span, argv + i + 1)) {
- fprintf(stderr, "error adding object\n");
- return false;
- }
- i += 1 + span;
- }
- } else {
- jobj = get_property_value(argv[0]);
- }
-
- if (key)
- json_object_object_add(jparent, key, jobj);
- else
- json_object_array_add(jparent, jobj);
-
- return true;
-}
-
-bool set_property_obj(json_object *jparent, int argc, char *argv[])
-{
- int i, span;
- const char *key;
-
- for (i = 0; i < argc; ) {
-
- key = argv[i];
- if (!strcmp(key, "{") || !strcmp(key, "[")) {
- fprintf(stderr, "Bad object start {\n");
- return false;
- }
- i++;
-
- if (i > (argc - 1)) {
- fprintf(stderr, "out of arguments on key %s\n", key);
- return false;
- }
-
- span = next_span(i, argc, argv);
- if (span < 0) {
- fprintf(stderr, "bad nesting\n");
- return false;
- }
-
- if (!add_property_value(jparent, key, span, argv + i)) {
- fprintf(stderr, "error adding property\n");
- return false;
- }
- i += span;
- }
-
- return true;
-}
-
-static int call_get_set_property(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jobj, *jprop = NULL;
- const char *type;
- int min_argc;
-
- if (argc < 1)
- return -1;
-
- type = argv[0];
- /* global or technology or service */
- if (strcmp(type, "global") && strcmp(type, "technology") &&
- strcmp(type, "service")) {
- fprintf(stderr, "unknown property type %s\n", type);
- return -1;
- }
-
- /* minimum is get global */
- min_argc = 1;
-
- /* technology or service have extra argument */
- if (!strcmp(type, "technology") || !strcmp(type, "service"))
- min_argc++;
-
- /* set property must have an argument */
- min_argc += !strcmp(c->verb, "set_property") ? 2 : 0;
-
- if (argc < min_argc) {
- fprintf(stderr, "not enough arguments\n");
- return -1;
- }
-
- jobj = json_object_new_object();
-
- argc--;
- argv++;
-
- if (!strcmp(type, "technology")) {
- json_object_object_add(jobj, "technology",
- json_object_new_string(argv[0]));
- argc--;
- argv++;
- } else if (!strcmp(type, "service")) {
- json_object_object_add(jobj, "service",
- json_object_new_string(argv[0]));
- argc--;
- argv++;
- }
-
- /* get is array, set is object */
- if (!strcmp(c->verb, "get_property")) {
- if (argc > 0) {
- jprop = json_object_new_array();
- get_property_obj(jprop, argc, argv);
- }
- } else {
- jprop = json_object_new_object();
- set_property_obj(jprop, argc, argv);
- }
-
- if (jprop)
- json_object_object_add(jobj, "properties", jprop);
-
- return do_call(s, c, jobj);
-}
-
-static void on_agent_response_reply(void *closure, struct afb_wsj1_msg *msg)
-{
- on_reply(closure, "agent_response", msg);
-}
-
-static int call_agent_response(struct state *s, const struct cmd *c, int argc, char *argv[])
-{
- json_object *jresp = NULL, *jprop = NULL;
- const char *method;
- const char *propname;
- int id;
-
- if (argc < 3)
- return -1;
-
- method = *argv++;
- argc--;
-
- id = (int)strtol(*argv++, NULL, 10);
- argc--;
-
- if (id <= 0) {
- fprintf(stderr, "bad agent response id %d\n", id);
- return -1;
- }
-
- propname = NULL;
- if (!strcmp(method, "request-input")) {
- propname = "fields";
- } else {
- fprintf(stderr, "unknown agent response method '%s'\n",
- method);
- return -1;
- }
-
- jresp = json_object_new_object();
- json_object_object_add(jresp, "method",
- json_object_new_string(method));
- json_object_object_add(jresp, "id",
- json_object_new_int(id));
-
- if (argc > 0) {
- jprop = json_object_new_object();
- set_property_obj(jprop, argc, argv);
- json_object_object_add(jresp, propname, jprop);
- }
-
- return do_call(s, c, jresp);
-}
-
-
-static const struct cmd cmds[] = {
- {
- .verb = "ping",
- .call = call_void,
- .reply = on_ping_reply,
- }, {
- .verb = "subscribe",
- .call = call_subscribe_unsubscribe,
- .reply = on_subscribe_reply,
- }, {
- .verb = "unsubscribe",
- .call = call_subscribe_unsubscribe,
- .reply = on_unsubscribe_reply,
- }, {
- .verb = "state",
- .call = call_void,
- .reply = on_state_reply,
- }, {
- .verb = "technologies",
- .call = call_void,
- .reply = on_technologies_reply,
- }, {
- .verb = "services",
- .call = call_void,
- .reply = on_services_reply,
- }, {
- .verb = "enable_technology",
- .call = call_technology_arg,
- .reply = on_enable_technology_reply,
- }, {
- .verb = "disable_technology",
- .call = call_technology_arg,
- .reply = on_disable_technology_reply,
- }, {
- .verb = "scan_services",
- .call = call_technology_arg,
- .reply = on_scan_services_reply,
- }, {
- .verb = "offline",
- .call = call_offline,
- .reply = on_offline_reply,
- }, {
- .verb = "connect_service",
- .call = call_service_arg,
- .reply = on_connect_service_reply,
- }, {
- .verb = "disconnect_service",
- .call = call_service_arg,
- .reply = on_disconnect_service_reply,
- }, {
- .verb = "remove_service",
- .call = call_service_arg,
- .reply = on_remove_service_reply,
- }, {
- .verb = "move_service",
- .call = call_move_service,
- .reply = on_move_service_reply,
- }, {
- .verb = "set_property",
- .call = call_get_set_property,
- .reply = on_set_property_reply,
- }, {
- .verb = "get_property",
- .call = call_get_set_property,
- .reply = on_get_property_reply,
- }, {
- .verb = "agent_response",
- .call = call_agent_response,
- .reply = on_agent_response_reply,
- },
- { }
-};
-
-static int call_cmd(struct state *s, int argc, char *argv[])
-{
- const struct cmd *c;
- const char *verb;
-
- /* first argument is verb */
- if (argc < 1 || !argv[0]) {
- if (!s->interactive)
- fprintf(stderr, "No verb given\n");
- goto out_err;
- }
- verb = argv[0];
- argv++;
- argc--;
-
- for (c = cmds; c->verb; c++) {
- if (!strcmp(verb, c->verb))
- return c->call(s, c, argc, argv);
- }
-
- if (!s->interactive)
- fprintf(stderr, "Unknown API verb \"%s\"\n", verb);
-out_err:
-
- if (!s->interactive)
- sd_event_exit(s->loop, EXIT_FAILURE);
-
- return -1;
-}
-
-static struct option opts[] = {
- { "url", required_argument, 0, 'u' },
- { "port", required_argument, 0, 'p' },
- { "token", required_argument, 0, 't' },
- { "api", required_argument, 0, 'a' },
- { "noexit", no_argument, 0, 'x' },
- { "debug", no_argument, 0, 'd' },
- { "help", no_argument, 0, 'h' },
- { }
-};
-
-#define DEFAULT_URL "ws://localhost"
-#define DEFAULT_PORT 1234
-#define DEFAULT_TOKEN "HELLO"
-#define DEFAULT_API "network-manager"
-#define DEFAULT_DEBUG true
-
-static void usage(int status, const char *arg0)
- __attribute__((__noreturn__));
-
-static void usage(int status, const char *arg0)
-{
- const char *name = strrchr(arg0, '/');
- FILE *outf = status ? stderr : stdout;
-
- name = name ? name + 1 : arg0;
-
- fprintf(outf, "usage: %s <options> [arguments]\n", name);
- fprintf(outf, " options are:\n");
- fprintf(outf, " -u, --url=X URL to connect to (default %s)\n", DEFAULT_URL);
- fprintf(outf, " -p, --port=X Port to use for connection (default %d)\n", DEFAULT_PORT);
- fprintf(outf, " -t, --token=X Token to use (default %s)\n", DEFAULT_TOKEN);
- fprintf(outf, " -a, --api=X API to use (default %s)\n", DEFAULT_API);
- fprintf(outf, " -x, --noexit Do not exit in non-interactive mode (events)\n");
- fprintf(outf, " -d, --debug Enable debug printouts\n");
- fprintf(outf, " -h, -?, --help Display this help\n");
-
- exit(status);
-}
-
-/* entry function */
-int main(int argc, char **argv)
-{
- int rc, ret, cc = 0, option_index;
- const char *name;
- struct state state, *s = &state;
-
- memset(s, 0, sizeof(*s));
- s->url = DEFAULT_URL;
- s->port = DEFAULT_PORT;
- s->token = DEFAULT_TOKEN;
- s->api = DEFAULT_API;
- s->debug = DEFAULT_DEBUG;
-
- s->interactive = false;
- s->noexit = false;
-
- while ((cc = getopt_long(argc, argv, "u:p:t:a:xdh?", opts,
- &option_index)) != -1) {
-
- if (cc == 0 && option_index >= 0) {
- name = opts[option_index].name;
- if (!name)
- continue;
- /* we don't have long options without short ones */
- usage(EXIT_FAILURE, argv[0]);
- }
-
- switch (cc) {
- case 'u':
- s->url = optarg;
- break;
- case 'p':
- s->port = atoi(optarg);
- break;
- case 't':
- s->token = optarg;
- break;
- case 'a':
- s->api = optarg;
- break;
- case 'x':
- s->noexit = true;
- break;
- case 'd':
- s->debug = true;
- break;
- case 'h':
- case '?':
- usage(0, argv[0]);
- break;
- }
- }
-
- /* no arguments left, interactive mode */
- if (optind >= argc) {
- printf("optind=%d\n", optind);
- printf("argc=%d\n", argc);
- s->interactive = true;
- }
-
- ret = EXIT_FAILURE;
-
- rc = asprintf(&s->uri, "%s:%d/api?token=%s", s->url, s->port, s->token);
- if (rc < 0) {
- fprintf(stderr, "Unable to build URI\n");
- goto out;
- }
-
- if (s->debug) {
- fprintf(stderr, "URI: \"%s\"\n", s->uri);
- fprintf(stderr, "API: \"%s\"\n", s->api);
- fprintf(stderr, "interactive: %s\n", s->interactive ? "true" : "false");
- fprintf(stderr, "noexit: %s\n", s->noexit ? "true" : "false");
- }
-
- /* get the default event loop */
- rc = sd_event_default(&s->loop);
- if (rc < 0) {
- fprintf(stderr, "connection to default event loop failed: %s\n", strerror(-rc));
- goto out_no_event;
- }
-
- /* connect the websocket wsj1 to the uri given by the first argument */
- s->wsj1 = afb_ws_client_connect_wsj1(s->loop, s->uri, &wsj1_itf, s);
- if (s->wsj1 == NULL) {
- fprintf(stderr, "connection to %s failed: %m\n", argv[1]);
- goto out_no_wsj1;
- }
-
- if (!s->interactive) {
- ret = call_cmd(s, argc - optind, argv + optind);
- if (ret < 0) {
- fprintf(stderr, "command failed\n");
- sd_event_exit(s->loop, EXIT_FAILURE);
- }
- } else {
- fprintf(stderr, "interactive mode not yet supported\n");
- sd_event_exit(s->loop, EXIT_FAILURE);
- }
-
- ret = sd_event_loop(s->loop);
-
- /* cleanup */
-
- afb_wsj1_unref(s->wsj1);
-out_no_wsj1:
- sd_event_unref(s->loop);
-out_no_event:
- free(s->uri);
-out:
- return ret;
-}
-
-/* called when wsj1 hangsup */
-static void on_wsj1_hangup(void *closure, struct afb_wsj1 *wsj1)
-{
- struct state *s = closure;
-
- printf("ON-HANGUP\n");
- fflush(stdout);
-
- s->hangup = true;
- sd_event_exit(s->loop, 0);
-}
-
-/* called when wsj1 receives a method invocation */
-static void on_wsj1_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
-{
- int rc;
-
- printf("ON-CALL %s/%s:\n%s\n", api, verb,
- json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
- JSON_C_TO_STRING_PRETTY));
- fflush(stdout);
- rc = afb_wsj1_reply_error_s(msg, "\"unimplemented\"", NULL);
- if (rc < 0)
- fprintf(stderr, "replying failed: %m\n");
-}
-
-/* called when wsj1 receives an event */
-static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
-{
- printf("ON-EVENT %s:\n%s\n", event,
- json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
- JSON_C_TO_STRING_PRETTY));
- fflush(stdout);
-}