From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 4220A4CB5 for ; Thu, 23 Aug 2018 14:08:35 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Aug 2018 05:08:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,278,1531810800"; d="scan'208";a="256613870" Received: from silpixa00399503.ir.intel.com ([10.237.222.102]) by fmsmga005.fm.intel.com with ESMTP; 23 Aug 2018 05:08:33 -0700 From: Ciara Power To: harry.van.haaren@intel.com, brian.archbold@intel.com, emma.kenny@intel.com, ciara.power@intel.com Cc: dev@dpdk.org Date: Thu, 23 Aug 2018 13:08:09 +0100 Message-Id: <1535026093-101872-8-git-send-email-ciara.power@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1535026093-101872-1-git-send-email-ciara.power@intel.com> References: <1535026093-101872-1-git-send-email-ciara.power@intel.com> Subject: [dpdk-dev] [PATCH 07/11] telemetry: add tests for telemetry api X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Aug 2018 12:08:35 -0000 This patch adds all tests for the Telemetry API. The tests added include a parser test, selftest, and socket messaging tests. The parser tests pass valid and invalid messages to the parser to ensure the correct return values are received. The selftest tests basic functions in the Telemetry API such as registering, unregistering, and initialisation. The socket messaging tests pass messages through the socket and validates the return message, to ensure the Telemetry API is responding correctly. Signed-off-by: Ciara Power Signed-off-by: Brian Archbold --- drivers/telemetry/telemetry/telemetry_driver.c | 7 + lib/librte_telemetry/Makefile | 1 + lib/librte_telemetry/meson.build | 4 +- lib/librte_telemetry/rte_telemetry.c | 616 +++++++++++++++++++++- lib/librte_telemetry/rte_telemetry.h | 12 + lib/librte_telemetry/rte_telemetry_internal.h | 3 + lib/librte_telemetry/rte_telemetry_parser_test.c | 574 ++++++++++++++++++++ lib/librte_telemetry/rte_telemetry_parser_test.h | 39 ++ lib/librte_telemetry/rte_telemetry_socket_tests.h | 36 ++ lib/librte_telemetry/rte_telemetry_version.map | 1 + 10 files changed, 1290 insertions(+), 3 deletions(-) create mode 100644 lib/librte_telemetry/rte_telemetry_parser_test.c create mode 100644 lib/librte_telemetry/rte_telemetry_parser_test.h create mode 100644 lib/librte_telemetry/rte_telemetry_socket_tests.h diff --git a/drivers/telemetry/telemetry/telemetry_driver.c b/drivers/telemetry/telemetry/telemetry_driver.c index c56f60c..125a89c 100644 --- a/drivers/telemetry/telemetry/telemetry_driver.c +++ b/drivers/telemetry/telemetry/telemetry_driver.c @@ -15,6 +15,13 @@ telemetry_probe(struct rte_vdev_device *vdev) int ret; RTE_SET_USED(vdev); + ret = rte_telemetry_selftest(); + if (ret < 0) { + printf("Error - Selftest failed\n"); + return -1; + } + printf("Success - Selftest passed\n"); + ret = rte_telemetry_init(rte_socket_id()); if (ret < 0) { printf("Error - Telemetry initialisation failed\n"); diff --git a/lib/librte_telemetry/Makefile b/lib/librte_telemetry/Makefile index df8fdd9..d766c82 100644 --- a/lib/librte_telemetry/Makefile +++ b/lib/librte_telemetry/Makefile @@ -20,6 +20,7 @@ LIBABIVER := 1 # library source files SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) := rte_telemetry.c SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += rte_telemetry_parser.c +SRCS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += rte_telemetry_parser_test.c # export include files SYMLINK-$(CONFIG_RTE_LIBRTE_TELEMETRY)-include := rte_telemetry.h diff --git a/lib/librte_telemetry/meson.build b/lib/librte_telemetry/meson.build index 7450f96..57dd83d 100644 --- a/lib/librte_telemetry/meson.build +++ b/lib/librte_telemetry/meson.build @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation -sources = files('rte_telemetry.c', 'rte_telemetry_parser.c') -headers = files('rte_telemetry.h', 'rte_telemetry_internal.h', 'rte_telemetry_parser.h') +sources = files('rte_telemetry.c', 'rte_telemetry_parser.c', 'rte_telemetry_parser_test.c') +headers = files('rte_telemetry.h', 'rte_telemetry_internal.h', 'rte_telemetry_parser.h', 'rte_telemetry_parser_test.h') deps += ['metrics', 'ethdev'] cflags += '-DALLOW_EXPERIMENTAL_API' jansson = cc.find_library('jansson', required: true) diff --git a/lib/librte_telemetry/rte_telemetry.c b/lib/librte_telemetry/rte_telemetry.c index ba04d3d..ecf644b 100644 --- a/lib/librte_telemetry/rte_telemetry.c +++ b/lib/librte_telemetry/rte_telemetry.c @@ -16,16 +16,34 @@ #include "rte_telemetry.h" #include "rte_telemetry_internal.h" #include "rte_telemetry_parser.h" +#include "rte_telemetry_parser_test.h" +#include "rte_telemetry_socket_tests.h" #define BUF_SIZE 1024 #define ACTION_POST 1 #define SLEEP_TIME 10 #define DEFAULT_DPDK_PATH "/var/run/.rte_telemetry" +#define SELFTEST_VALID_CLIENT "/var/run/valid_client" +#define SELFTEST_INVALID_CLIENT "/var/run/invalid_client" +#define SOCKET_TEST_CLIENT_PATH "/var/run/client" const char *socket_path = DEFAULT_DPDK_PATH; static telemetry_impl *static_telemetry; +struct telemetry_message_test { + char *test_name; + int (*test_func_ptr)(struct telemetry_impl *telemetry, int fd); +}; + +struct json_data { + char *status_code; + char *data; + int port; + char *stat_name; + int stat_value; +}; + int32_t rte_telemetry_check_port_activity(int port_id) { @@ -634,7 +652,7 @@ rte_telemetry_reg_ethdev_to_metrics(uint16_t port_id) static int32_t rte_telemetry_initial_accept(struct telemetry_impl *telemetry) { - int pid; + int pid, ret; RTE_ETH_FOREACH_DEV(pid) { telemetry->reg_index = @@ -648,6 +666,17 @@ rte_telemetry_initial_accept(struct telemetry_impl *telemetry) return -1; } telemetry->metrics_register_done = 1; + ret = rte_telemetry_socket_messaging_testing(telemetry->reg_index, + telemetry->server_fd); + if (ret < 0) + return -1; + + ret = rte_telemetry_parser_test(telemetry); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Parser Tests Failed\n"); + return -1; + } + TELEMETRY_LOG_INFO("Success - All Parser Tests Passed\n"); return 0; } @@ -1108,6 +1137,591 @@ rte_telemetry_parse_client_message(struct telemetry_impl *telemetry, char *buf) return -1; } +int32_t +rte_telemetry_dummy_client_socket(const char *valid_client_path) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Error - Test socket creation failure\n"); + return -1; + } + struct sockaddr_un addr = {0}; + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, valid_client_path, sizeof(addr.sun_path)); + unlink(valid_client_path); + + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + TELEMETRY_LOG_ERR("Error - Test socket binding failure\n"); + return -1; + } + if (listen(sockfd, 1) < 0) { + TELEMETRY_LOG_ERR("Error - Listen failure\n"); + return -1; + } + return sockfd; +} + +int32_t +rte_telemetry_selftest(void) +{ + const char *invalid_client_path = SELFTEST_INVALID_CLIENT; + const char *valid_client_path = SELFTEST_VALID_CLIENT; + int ret, sockfd; + + TELEMETRY_LOG_INFO("Selftest\n"); + + ret = rte_telemetry_init(rte_socket_id()); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Valid initialisation test" + " failed\n"); + return -1; + } + TELEMETRY_LOG_INFO("Success - Valid initialisation test passed\n"); + + ret = rte_telemetry_init(rte_socket_id()); + if (ret != -EALREADY) { + TELEMETRY_LOG_ERR("Error - Invalid initialisation test " + "failed\n"); + return -1; + } + TELEMETRY_LOG_INFO("Success - Invalid initialisation test passed\n"); + + ret = rte_telemetry_unregister_client(static_telemetry, + invalid_client_path); + if (ret != -EPERM) { + TELEMETRY_LOG_ERR("Error - Invalid unregister test failed\n"); + return -1; + } + TELEMETRY_LOG_INFO("Success - Invalid unregister test passed\n"); + + sockfd = rte_telemetry_dummy_client_socket(valid_client_path); + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Error - Test socket creation failed\n"); + return -1; + } + + ret = rte_telemetry_register_client(static_telemetry, + valid_client_path); + if (ret != 0) { + TELEMETRY_LOG_ERR("Error - Valid register test failed: %i\n", + ret); + return -1; + } + accept(sockfd, NULL, NULL); + TELEMETRY_LOG_INFO("Success - Valid register test passed\n"); + + ret = rte_telemetry_register_client(static_telemetry, + valid_client_path); + if (ret != -EINVAL) { + TELEMETRY_LOG_ERR("Error - Invalid register test failed: %i\n", + ret); + return -1; + } + TELEMETRY_LOG_INFO("Success - Invalid register test passed\n"); + + ret = rte_telemetry_unregister_client(static_telemetry, + invalid_client_path); + if (ret != -1) { + TELEMETRY_LOG_ERR("Error - Invalid unregister test failed: " + "%i\n", ret); + return -1; + } + TELEMETRY_LOG_INFO("Success - Invalid unregister test passed\n"); + + ret = rte_telemetry_unregister_client(static_telemetry, + valid_client_path); + if (ret != 0) { + TELEMETRY_LOG_ERR("Error - Valid unregister test failed: %i" + "\n", ret); + return -1; + } + TELEMETRY_LOG_INFO("Success - Valid unregister test passed\n"); + + ret = rte_telemetry_cleanup(); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - cleanup() test failed\n"); + return -1; + } + TELEMETRY_LOG_INFO("Success - Valid cleanup test passed\n"); + + return 0; +} + +int32_t +rte_telemetry_socket_messaging_testing(int index, int socket) +{ + struct telemetry_impl *telemetry = calloc(1, sizeof(telemetry_impl)); + int fd, bad_send_fd, send_fd, bad_fd, bad_recv_fd, recv_fd, ret; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - could not initialize " + "Telemetry API\n"); + return -1; + } + telemetry->server_fd = socket; + telemetry->reg_index = index; + TELEMETRY_LOG_INFO("Beginning Telemetry socket message Selftest\n"); + rte_telemetry_socket_test_setup(telemetry, &send_fd, &recv_fd); + TELEMETRY_LOG_INFO("Register valid client test\n"); + + ret = rte_telemetry_socket_register_test(telemetry, &fd, send_fd, + recv_fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Register valid client test " + "failed!\n"); + free(telemetry); + return -1; + } + TELEMETRY_LOG_INFO("Success - Register valid client test passed!\n"); + + TELEMETRY_LOG_INFO("Register invalid/same client test\n"); + ret = rte_telemetry_socket_test_setup(telemetry, &bad_send_fd, + &bad_recv_fd); + ret = rte_telemetry_socket_register_test(telemetry, &bad_fd, + bad_send_fd, bad_recv_fd); + if (!ret) { + TELEMETRY_LOG_ERR("Error - Register invalid/same client test " + "failed!\n"); + free(telemetry); + return -1; + } + TELEMETRY_LOG_INFO("Success - Register invalid/same client test " + "passed!\n"); + + ret = rte_telemetry_json_socket_message_test(telemetry, fd); + if (ret < 0) { + free(telemetry); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd, + int send_fd, int recv_fd) +{ + int ret; + char good_req_string[BUF_SIZE]; + + snprintf(good_req_string, sizeof(good_req_string), + "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\"" + ":\"%s\"}}", SOCKET_TEST_CLIENT_PATH); + + listen(recv_fd, 1); + ret = send(send_fd, good_req_string, strlen(good_req_string), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not send message over " + "socket\n"); + return -1; + } + rte_telemetry_run(telemetry); + if (telemetry->register_fail_count != 0) + return -1; + *fd = accept(recv_fd, NULL, NULL); + return 0; +} + +int32_t +rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd, + int *recv_fd) +{ + int ret; + const char *client_path = SOCKET_TEST_CLIENT_PATH; + *send_fd = socket(AF_UNIX, SOCK_STREAM, 0); + *recv_fd = socket(AF_UNIX, SOCK_STREAM, 0); + + listen(telemetry->server_fd, 5); + struct sockaddr_un addr = {0}; + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); + ret = connect(*send_fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - could not connect socket\n"); + return -1; + } + telemetry->accept_fd = accept(telemetry->server_fd, NULL, NULL); + + struct sockaddr_un addrs = {0}; + addrs.sun_family = AF_UNIX; + strlcpy(addrs.sun_path, client_path, sizeof(addrs.sun_path)); + unlink(client_path); + + ret = bind(*recv_fd, (struct sockaddr *)&addrs, sizeof(addrs)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - could not bind socket\n"); + return -1; + } + + return 0; +} + +static int32_t +rte_telemetry_stat_parse(char *buf, struct json_data *json_data_struct) +{ + json_error_t error; + json_t *root = json_loads(buf, 0, &error); + int arraylen, i; + json_t *status, *dataArray, *port, *stats, *name, *value, + *dataArrayObj, *statsArrayObj; + + stats = NULL; + port = NULL; + name = NULL; + + if (buf == NULL) { + TELEMETRY_LOG_ERR("Error - JSON message is NULL\n"); + return -EINVAL; + } + + if (!root) { + TELEMETRY_LOG_ERR("Error - Could not load JSON object from " + "data passed in : %s\n", error.text); + return -EPERM; + } else if (!json_is_object(root)) { + TELEMETRY_LOG_ERR("Error - JSON Request is not a JSON " + "object\n"); + json_decref(root); + return -EINVAL; + } + + status = json_object_get(root, "status_code"); + if (!status) { + TELEMETRY_LOG_ERR("Error - Request does not have status " + "field\n"); + return -EINVAL; + } else if (!json_is_string(status)) { + TELEMETRY_LOG_ERR("Error - Status value is not a String\n"); + return -EINVAL; + } + + json_data_struct->status_code = strdup(json_string_value(status)); + + dataArray = json_object_get(root, "data"); + if (!dataArray) { + TELEMETRY_LOG_ERR("Error - Request does not have data field\n"); + return -EINVAL; + } + arraylen = json_array_size(dataArray); + if (arraylen == 0) { + json_data_struct->data = "null"; + return -EINVAL; + } + + for (i = 0; i < arraylen; i++) { + dataArrayObj = json_array_get(dataArray, i); + port = json_object_get(dataArrayObj, "port"); + stats = json_object_get(dataArrayObj, "stats"); + } + + if (!port) { + TELEMETRY_LOG_ERR("Error - Request does not have port field\n"); + return -EINVAL; + } + if (!json_is_integer(port)) { + TELEMETRY_LOG_ERR("Error - Port value is not an integer\n"); + return -EINVAL; + } + + json_data_struct->port = json_integer_value(port); + + if (!stats) { + TELEMETRY_LOG_ERR("Error - Request does not have stats " + "field\n"); + return -EINVAL; + } + + arraylen = json_array_size(stats); + for (i = 0; i < arraylen; i++) { + statsArrayObj = json_array_get(stats, i); + name = json_object_get(statsArrayObj, "name"); + value = json_object_get(statsArrayObj, "value"); + } + if (!name) { + TELEMETRY_LOG_ERR("Error - Request does not have name field\n"); + return -EINVAL; + } + if (!json_is_string(name)) { + TELEMETRY_LOG_ERR("Error - Stat name value is not a string\n"); + return -EINVAL; + } + json_data_struct->stat_name = strdup(json_string_value(name)); + + if (!value) { + TELEMETRY_LOG_ERR("Error - Request does not have value " + "field\n"); + return -EINVAL; + } + if (!json_is_integer(value)) { + TELEMETRY_LOG_ERR("Error - Stat value is not an integer\n"); + return -EINVAL; + } + json_data_struct->stat_value = json_integer_value(value); + return 0; +} + +static void +rte_telemetry_free_test_data(struct json_data *data) +{ + free(data->status_code); + free(data->stat_name); + free(data); +} + +int32_t +rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + struct json_data *data_struct; + const char *status = "Status OK: 200"; + int port = 0; + const char *name = "rx_good_packets"; + int value = 0; + int fail_count = 0; + const char *valid_json_message = "{\"action\":0,\"command\":" + "\"ports_stats_values_by_name\",\"data\":{\"ports\"" + ":[0],\"stats\":[\"rx_good_packets\"]}}"; + + ret = send(fd, valid_json_message, strlen(valid_json_message), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not send message over " + "socket\n"); + return -1; + } + rte_telemetry_run(telemetry); + int buffer_read = 0; + errno = 0; + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Error - Read error\n"); + return -1; + } + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not parse stats\n"); + fail_count++; + } + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR(" Error - Status code is invalid\n"); + fail_count++; + } + if (data_struct->port != port) { + TELEMETRY_LOG_ERR("Error - Port is invalid\n"); + fail_count++; + } + if (strcmp(data_struct->stat_name, name) != 0) { + TELEMETRY_LOG_ERR("Error - Stat name is invalid\n"); + fail_count++; + } + if (data_struct->stat_value != value) { + TELEMETRY_LOG_ERR("Error - Stat value is invalid\n"); + fail_count++; + } + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed valid JSON message test " + "passed\n"); + return 0; +} + +int32_t +rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + const char *invalid_json = "{]"; + const char *status = "Status Error: Unknown"; + const char *data = "null"; + struct json_data *data_struct; + int buffer_read = 0; + errno = 0; + + ret = send(fd, invalid_json, strlen(invalid_json), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not send message over " + "socket\n"); + return -1; + } + + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Error - Read error\n"); + return -1; + } + buf[buffer_read] = '\0'; + + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Error - Could not parse stats\n"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Error - Status code is invalid\n"); + fail_count++; + } + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Error - Data status is invalid\n"); + fail_count++; + } + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed invalid JSON message test\n"); + return 0; +} + +int32_t +rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + char *status = "Status Error: Invalid Argument 404"; + char *data = "null"; + struct json_data *data_struct; + const char *invalid_contents = "{\"action\":0,\"command\":" + "\"ports_stats_values_by_name\",\"data\":{\"ports\"" + ":[0],\"stats\":[\"some_invalid_param\"," + "\"another_invalid_param\"]}}"; + int buffer_read = 0; + errno = 0; + + ret = send(fd, invalid_contents, strlen(invalid_contents), 0); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not send message over " + "socket\n"); + return -1; + } + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Error - Read error\n"); + return -1; + } + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Error - Could not parse stats\n"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Error - Status code is invalid\n"); + fail_count++; + } + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Error - Data status is invalid\n"); + fail_count++; + } + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed invalid JSON content test\n"); + return 0; +} + +int32_t +rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd) +{ + int ret; + char buf[BUF_SIZE]; + int fail_count = 0; + const char *status = "Status Error: Invalid Argument 404"; + char *data = "null"; + struct json_data *data_struct; + const char *empty_json = "{}"; + int buffer_read = 0; + errno = 0; + + ret = (send(fd, empty_json, strlen(empty_json), 0)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not send message over " + "socket\n"); + return -1; + } + rte_telemetry_run(telemetry); + buffer_read = recv(fd, buf, BUF_SIZE-1, 0); + if (buffer_read == -1) { + TELEMETRY_LOG_ERR("Error - Read error\n"); + return -1; + } + buf[buffer_read] = '\0'; + data_struct = calloc(1, sizeof(struct json_data)); + ret = rte_telemetry_stat_parse(buf, data_struct); + + if (ret < 0) + TELEMETRY_LOG_ERR("Error - Could not parse stats\n"); + + if (strcmp(data_struct->status_code, status) != 0) { + TELEMETRY_LOG_ERR("Error - Status code is invalid\n"); + fail_count++; + } + if (strcmp(data_struct->data, data) != 0) { + TELEMETRY_LOG_ERR("Error - Data status is invalid\n"); + fail_count++; + } + rte_telemetry_free_test_data(data_struct); + if (fail_count > 0) + return -1; + + TELEMETRY_LOG_INFO("Success - Passed JSON empty message test\n"); + return 0; +} + +int32_t +rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, int fd) +{ + uint16_t i; + int ret, fail_count; + + fail_count = 0; + struct telemetry_message_test socket_json_tests[] = { + {.test_name = "Invalid JSON test", + .test_func_ptr = rte_telemetry_invalid_json_test}, + {.test_name = "Valid JSON test", + .test_func_ptr = rte_telemetry_valid_json_test}, + {.test_name = "JSON contents test", + .test_func_ptr = rte_telemetry_json_contents_test}, + {.test_name = "JSON empty tests", + .test_func_ptr = rte_telemetry_json_empty_test} + }; + +#define NUM_TESTS (sizeof(socket_json_tests)/sizeof(socket_json_tests[0])) + + for (i = 0; i < NUM_TESTS; i++) { + TELEMETRY_LOG_INFO("%s\n", + socket_json_tests[i].test_name); + ret = (socket_json_tests[i].test_func_ptr) + (telemetry, fd); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - %s failed\n", + socket_json_tests[i].test_name); + fail_count++; + } + } + if (fail_count > 0) { + TELEMETRY_LOG_ERR("Error - Failed %i JSON socket message " + "test(s)", fail_count); + return -1; + } + TELEMETRY_LOG_INFO("Success - All JSON tests passed\n"); + return 0; +} + int telemetry_log_level; RTE_INIT(rte_telemetry_log_init); diff --git a/lib/librte_telemetry/rte_telemetry.h b/lib/librte_telemetry/rte_telemetry.h index b691845..4f187b7 100644 --- a/lib/librte_telemetry/rte_telemetry.h +++ b/lib/librte_telemetry/rte_telemetry.h @@ -37,4 +37,16 @@ rte_telemetry_init(uint32_t socket_id); int32_t rte_telemetry_cleanup(void); +/** + * Runs various tests to ensure telemetry initialisation and register/unregister + * functions are working correctly. + * + * @return + * 0 on success when all tests have passed + * @return + * -1 on failure when the test has failed + */ +int32_t +rte_telemetry_selftest(void); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_internal.h b/lib/librte_telemetry/rte_telemetry_internal.h index ef417f2..3e21b79 100644 --- a/lib/librte_telemetry/rte_telemetry_internal.h +++ b/lib/librte_telemetry/rte_telemetry_internal.h @@ -65,4 +65,7 @@ int32_t rte_telemetry_send_ports_stats_values(uint32_t *metric_ids, int num_metric_ids, uint32_t *port_ids, int num_port_ids, struct telemetry_impl *telemetry); +int32_t +rte_telemetry_socket_messaging_testing(int index, int socket); + #endif diff --git a/lib/librte_telemetry/rte_telemetry_parser_test.c b/lib/librte_telemetry/rte_telemetry_parser_test.c new file mode 100644 index 0000000..4fa442d --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser_test.c @@ -0,0 +1,574 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rte_telemetry_parser.h" + +#define ACTION_GET 0 +#define ACTION_DELETE 2 + +#define INV_ACTION_VAL 0 +#define INV_COMMAND_VAL 1 +#define INV_DATA_VAL 2 +#define INV_ACTION_FIELD 3 +#define INV_COMMAND_FIELD 4 +#define INV_DATA_FIELD 5 +#define INV_JSON_FORMAT 6 +#define VALID_REQ 7 + + +#define TEST_CLIENT "/var/run/test_client" + +int32_t +rte_telemetry_create_test_socket(struct telemetry_impl *telemetry, + const char *test_client_path) +{ + + int ret, sockfd; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + TELEMETRY_LOG_ERR("Error - Test socket creation failure\n"); + return -1; + } + + struct sockaddr_un addr = {0}; + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, test_client_path, sizeof(addr.sun_path)); + unlink(test_client_path); + + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + TELEMETRY_LOG_ERR("Error - Test socket binding failure\n"); + return -1; + } + + if (listen(sockfd, 1) < 0) { + TELEMETRY_LOG_ERR("Error - Listen failure\n"); + return -1; + } + + ret = rte_telemetry_register_client(telemetry, test_client_path); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Register dummy client failed: %i", + ret); + return -1; + } + + ret = accept(sockfd, NULL, NULL); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Socket accept failed\n"); + return -1; + } + + struct telemetry_client *client; + TAILQ_FOREACH(client, &telemetry->client_list_head, client_list) + telemetry->request_client = client; + + return 0; +} + +int32_t +rte_telemetry_format_port_stat_ids(int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, json_t **data) +{ + + int ret; + json_t *stat_names_json_array = NULL; + json_t *port_ids_json_array = NULL; + if (num_port_ids < 0) { + TELEMETRY_LOG_ERR("Error - Port Ids Count invalid\n"); + goto fail; + } + + *data = json_object(); + if (!*data) { + TELEMETRY_LOG_ERR("Error - Data json object creation failed\n"); + goto fail; + } + + port_ids_json_array = json_array(); + if (!port_ids_json_array) { + TELEMETRY_LOG_ERR("Error - port_ids_json_array creation " + "failed\n"); + goto fail; + } + + uint32_t i; + for (i = 0; i < (uint32_t) num_port_ids; i++) { + ret = json_array_append(port_ids_json_array, + json_integer(port_ids[i])); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - JSON array creation " + "failed\n"); + goto fail; + } + } + + ret = json_object_set_new(*data, "ports", port_ids_json_array); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting 'ports' value in data object" + " failed\n"); + goto fail; + } + + if (stat_names) { + + if (num_stat_names < 0) { + TELEMETRY_LOG_ERR("Error - Stat Names Count invalid\n"); + goto fail; + } + + stat_names_json_array = json_array(); + if (!stat_names_json_array) { + TELEMETRY_LOG_ERR("Error - stat_names_json_array " + "creation failed\n"); + goto fail; + } + + uint32_t i; + for (i = 0; i < (uint32_t) num_stat_names; i++) { + ret = json_array_append(stat_names_json_array, + json_string(stat_names[i])); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - JSON array creation " + " failed\n"); + goto fail; + } + } + + ret = json_object_set_new(*data, "stats", + stat_names_json_array); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting 'stats' value in " + "data object failed\n"); + goto fail; + } + + } + return 0; + +fail: + if (*data) + json_decref(*data); + if (stat_names_json_array) + json_decref(stat_names_json_array); + if (port_ids_json_array) + json_decref(port_ids_json_array); + return -1; +} + +int32_t +rte_telemetry_create_json_request(int action, char *command, + const char *client_path, int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, char **request, + int inv_choice) +{ + int ret; + json_t *root = json_object(); + + if (!root) { + TELEMETRY_LOG_ERR("Error - Could not create root json " + "object\n"); + goto fail; + } + + if (inv_choice == INV_ACTION_FIELD) { + ret = json_object_set_new(root, "ac--on", json_integer(action)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting invalid action " + "field in root object failed\n"); + goto fail; + } + } else { + ret = json_object_set_new(root, "action", json_integer(action)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting valid action field " + "in root object failed\n"); + goto fail; + } + } + + if (inv_choice == INV_COMMAND_FIELD) { + ret = json_object_set_new(root, "co---nd", + json_string(command)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting invalid command " + "field in root object failed\n"); + goto fail; + } + } else { + ret = json_object_set_new(root, "command", + json_string(command)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting valid command " + "field in root object failed\n"); + goto fail; + } + } + + json_t *data = json_null(); + if (client_path) { + data = json_object(); + if (!data) { + TELEMETRY_LOG_ERR("Error - Data json object creation " + "failed\n"); + goto fail; + } + + ret = json_object_set_new(data, "client_path", + json_string(client_path)); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting valid client_path " + "field in data object failed\n"); + goto fail; + } + + } else if (port_ids) { + ret = rte_telemetry_format_port_stat_ids(port_ids, num_port_ids, + stat_names, num_stat_names, &data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Formatting Port/Stat " + "arrays failed\n"); + goto fail; + } + + } + + if (inv_choice == INV_DATA_FIELD) { + ret = json_object_set_new(root, "d--a", data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting invalid data " + "field in data object failed\n"); + goto fail; + } + } else { + ret = json_object_set_new(root, "data", data); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Setting valid data field " + "in data object failed\n"); + goto fail; + } + } + + *request = json_dumps(root, 0); + if (!*request) { + TELEMETRY_LOG_ERR("Error - Converting JSON root object to " + "char* failed\n"); + goto fail; + } + + json_decref(root); + return 0; + +fail: + if (root) + json_decref(root); + return -1; +} + +int32_t +rte_telemetry_send_get_ports_and_stats_request(struct telemetry_impl *telemetry, + int action_choice, char *command_choice, int inv_choice) +{ + int ret; + char *request; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + char *client_path_data = NULL; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command_choice = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + client_path_data = "INVALID_DATA"; + + ret = rte_telemetry_create_json_request(action_choice, command_choice, + client_path_data, NULL, -1, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not create JSON Request\n"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Warning - Could not parse JSON Request\n"); + return -1; + } + return 0; +} + +int32_t +rte_telemetry_send_get_ports_details_request(struct telemetry_impl *telemetry, + int action_choice, int *port_ids, int num_port_ids, int inv_choice) +{ + int ret; + char *request; + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + char *command = "ports_details"; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + port_ids = NULL; + + + ret = rte_telemetry_create_json_request(action_choice, command, NULL, + port_ids, num_port_ids, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not create JSON Request\n"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Warning - Could not parse JSON Request\n"); + return -1; + } + return 0; +} + +int32_t +rte_telemetry_send_stats_values_by_name_request(struct telemetry_impl + *telemetry, int action_choice, int *port_ids, int num_port_ids, + const char * const *stat_names, int num_stat_names, + int inv_choice) +{ + int ret; + char *request; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + char *command = "ports_stats_values_by_name"; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) { + port_ids = NULL; + stat_names = NULL; + } + + + ret = rte_telemetry_create_json_request(action_choice, command, NULL, + port_ids, num_port_ids, stat_names, num_stat_names, + &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not create JSON Request\n"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Warning - Could not parse JSON Request\n"); + return -1; + } + + return 0; +} + +int32_t +rte_telemetry_send_unreg_request(struct telemetry_impl *telemetry, + int action_choice, const char *client_path, int inv_choice) +{ + int ret; + char *request; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + char *command = "clients"; + + if (inv_choice == INV_ACTION_VAL) + action_choice = -1; + else if (inv_choice == INV_COMMAND_VAL) + command = "INVALID_COMMAND"; + else if (inv_choice == INV_DATA_VAL) + client_path = NULL; + + ret = rte_telemetry_create_json_request(action_choice, command, + client_path, NULL, -1, NULL, -1, &request, inv_choice); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not create JSON Request\n"); + return -1; + } + + if (inv_choice == INV_JSON_FORMAT) + request++; + + ret = rte_telemetry_parse(telemetry, request); + if (ret < 0) { + TELEMETRY_LOG_WARN("Warning - Could not parse JSON Request\n"); + return -1; + } + return 0; +} + +int32_t +rte_telemetry_parser_test(struct telemetry_impl *telemetry) +{ + int ret; + + if (!telemetry) { + TELEMETRY_LOG_ERR("Error - Telemetry argument has not been " + "initialised\n"); + return -EINVAL; + } + + const char *client_path = TEST_CLIENT; + ret = rte_telemetry_create_test_socket(telemetry, client_path); + if (ret < 0) { + TELEMETRY_LOG_ERR("Error - Could not create test request " + "client socket\n"); + return -1; + } + + int port_ids[] = {0, 1}; + int num_port_ids = RTE_DIM(port_ids); + + static const char * const stat_names[] = {"tx_good_packets", + "rx_good_packets"}; + int num_stat_names = RTE_DIM(stat_names); + + static const char * const test_types[] = { + "INVALID ACTION VALUE TESTS", + "INVALID COMMAND VALUE TESTS", + "INVALID DATA VALUE TESTS", + "INVALID ACTION FIELD TESTS", + "INVALID COMMAND FIELD TESTS", + "INVALID DATA FIELD TESTS", + "INVALID JSON FORMAT TESTS", + "VALID TESTS" + }; + + +#define NUM_TEST_TYPES (sizeof(test_types)/sizeof(const char * const)) + + uint32_t i; + for (i = 0; i < NUM_TEST_TYPES; i++) { + TELEMETRY_LOG_INFO("%s\n", + test_types[i]); + + ret = rte_telemetry_send_get_ports_and_stats_request(telemetry, + ACTION_GET, "ports", i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports valid test " + "failed\n"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports invalid test" + " failed\n"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports test passed\n"); + + ret = rte_telemetry_send_get_ports_details_request(telemetry, + ACTION_GET, port_ids, num_port_ids, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports details valid\n"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports details " + "invalid\n"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports details test passed\n"); + + ret = rte_telemetry_send_get_ports_and_stats_request(telemetry, + ACTION_GET, "port_stats", i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get port stats valid " + "test\n"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports stats invalid" + " test failed\n"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports stats test passed\n"); + + ret = rte_telemetry_send_stats_values_by_name_request(telemetry, + ACTION_GET, port_ids, num_port_ids, + stat_names, num_stat_names, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports stats values by" + " name valid test failed\n"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Get ports stats values by" + " name invalid test failed\n"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Get ports stats values by name" + " test passed\n"); + + ret = rte_telemetry_send_unreg_request(telemetry, ACTION_DELETE, + client_path, i); + if (ret != 0 && i == VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Deregister valid test " + "failed\n"); + return -EPERM; + } else if (ret != -1 && i != VALID_REQ) { + TELEMETRY_LOG_ERR("Error - Deregister invalid test" + " failed\n"); + return -EPERM; + } + + TELEMETRY_LOG_INFO("Success - Deregister test passed\n"); + } + + return 0; +} diff --git a/lib/librte_telemetry/rte_telemetry_parser_test.h b/lib/librte_telemetry/rte_telemetry_parser_test.h new file mode 100644 index 0000000..6ada852 --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_parser_test.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#ifndef _RTE_TELEMETRY_PARSER_TEST_H_ +#define _RTE_TELEMETRY_PARSER_TEST_H_ + +int32_t +rte_telemetry_parser_test(struct telemetry_impl *telemetry); + +int32_t +rte_telemetry_format_port_stat_ids(int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, json_t **data); + +int32_t +rte_telemetry_create_json_request(int action, char *command, + const char *client_path, int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, char **request, + int inv_choice); + +int32_t +rte_telemetry_send_get_ports_and_stats_request(struct telemetry_impl *telemetry, + int action_choice, char *command_choice, int inv_choice); + +int32_t +rte_telemetry_send_get_ports_details_request(struct telemetry_impl *telemetry, + int action_choice, int *port_ids, int num_port_ids, int inv_choice); + +int32_t +rte_telemetry_send_stats_values_by_name_request(struct telemetry_impl + *telemetry, int action_choice, int *port_ids, int num_port_ids, + const char * const stat_names, int num_stat_names, + int inv_choice); + +int32_t +rte_telemetry_send_unreg_request(int action_choice, const char *client_path, + int inv_choice); + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_socket_tests.h b/lib/librte_telemetry/rte_telemetry_socket_tests.h new file mode 100644 index 0000000..db9167c --- /dev/null +++ b/lib/librte_telemetry/rte_telemetry_socket_tests.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include + +#include "rte_telemetry_internal.h" + +#ifndef _RTE_TELEMETRY_SOCKET_TESTING_H_ +#define _RTE_TELEMETRY_SOCKET_TESTING_H_ + +int32_t +rte_telemetry_json_socket_message_test(struct telemetry_impl *telemetry, + int fd); + +int32_t +rte_telemetry_invalid_json_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_valid_json_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_json_contents_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_json_empty_test(struct telemetry_impl *telemetry, int fd); + +int32_t +rte_telemetry_socket_register_test(struct telemetry_impl *telemetry, int *fd, + int send_fd, int recv_fd); + +int32_t +rte_telemetry_socket_test_setup(struct telemetry_impl *telemetry, int *send_fd, + int *recv_fd); + +#endif diff --git a/lib/librte_telemetry/rte_telemetry_version.map b/lib/librte_telemetry/rte_telemetry_version.map index efd437d..5ce5680 100644 --- a/lib/librte_telemetry/rte_telemetry_version.map +++ b/lib/librte_telemetry/rte_telemetry_version.map @@ -2,5 +2,6 @@ DPDK_18.05 { global: rte_telemetry_init; + rte_telemetry_selftest; local: *; }; -- 2.7.4