From 48cc7d6cbc9552794e846200deaf679714ffa4eb Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Wed, 7 Jul 2021 10:40:07 +0200 Subject: - added rudimentary cmd helper (copied from testbed-helper), binary to start a testcase plugin, rudimentary testcase plugin --- src/include/gnunet_testing_plugin.h | 60 +++ src/testbed/Makefile.am | 32 ++ src/testbed/gnunet-cmd.c | 93 ++++ src/testbed/gnunet-helper-cmds.c | 581 +++++++++++++++++++++ src/testbed/plugin_testcmd.c | 87 +++ src/testbed/testbed_api.h | 5 + .../testbed_api_cmd_netjail_start_testbed.c | 7 +- src/testing/testing_api_loop.c | 47 +- 8 files changed, 899 insertions(+), 13 deletions(-) create mode 100644 src/include/gnunet_testing_plugin.h create mode 100644 src/testbed/gnunet-cmd.c create mode 100644 src/testbed/gnunet-helper-cmds.c create mode 100644 src/testbed/plugin_testcmd.c (limited to 'src') diff --git a/src/include/gnunet_testing_plugin.h b/src/include/gnunet_testing_plugin.h new file mode 100644 index 000000000..527f509ad --- /dev/null +++ b/src/include/gnunet_testing_plugin.h @@ -0,0 +1,60 @@ +/* + This file is part of GNUnet + Copyright (C) 2021 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * + * @author t3sserakt + * + * Plugin API to start test cases. + * + */ +#ifndef GNUNET_TESTING_PLUGIN_H +#define GNUNET_TESTING_PLUGIN_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +typedef void +(*GNUNET_TESTING_PLUGIN_StartTestCase) (); + +struct GNUNET_TESTING_PluginFunctions +{ + /** + * Closure for all of the callbacks. + */ + void *cls; + + GNUNET_TESTING_PLUGIN_StartTestCase start_testcase; +}; + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am index 79989bae7..8c4a6342b 100644 --- a/src/testbed/Makefile.am +++ b/src/testbed/Makefile.am @@ -6,6 +6,8 @@ if USE_COVERAGE XLIB = -lgcov endif +plugindir = $(libdir)/gnunet + libexecdir= $(pkglibdir)/libexec/ pkgcfgdir= $(pkgdatadir)/config.d/ @@ -21,6 +23,8 @@ if HAVE_SQLITE endif libexec_PROGRAMS = \ + gnunet-cmd \ + gnunet-helper-cmds \ gnunet-service-testbed \ gnunet-helper-testbed \ gnunet-daemon-testbed-blacklist \ @@ -33,6 +37,18 @@ bin_PROGRAMS = \ noinst_PROGRAMS = \ $(generate_underlay) +plugin_LTLIBRARIES = \ + libgnunet_plugin_testcmd.la + +libgnunet_plugin_testcmd_la_SOURCES = \ + plugin_testcmd.c +libgnunet_plugin_testcmd_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(LTLIBINTL) +libgnunet_plugin_testcmd_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + gnunet_service_testbed_SOURCES = \ gnunet-service-testbed.c gnunet-service-testbed.h \ gnunet-service-testbed_links.c gnunet-service-testbed_links.h \ @@ -70,6 +86,22 @@ gnunet_helper_testbed_LDADD = $(XLIB) \ libgnunettestbed.la \ $(LTLIBINTL) $(Z_LIBS) +gnunet_cmd_SOURCES = \ + gnunet-cmd.c +gnunet_cmd_LDADD = $(XLIB) \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + libgnunettestbed.la \ + $(LTLIBINTL) $(Z_LIBS) + +gnunet_helper_cmds_SOURCES = \ + gnunet-helper-cmds.c +gnunet_helper_cmds_LDADD = $(XLIB) \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + libgnunettestbed.la \ + $(LTLIBINTL) $(Z_LIBS) + gnunet_daemon_testbed_blacklist_SOURCES = gnunet-daemon-testbed-blacklist.c gnunet_daemon_testbed_blacklist_LDADD = $(XLIB) \ $(top_builddir)/src/transport/libgnunettransport.la \ diff --git a/src/testbed/gnunet-cmd.c b/src/testbed/gnunet-cmd.c new file mode 100644 index 000000000..477c3c454 --- /dev/null +++ b/src/testbed/gnunet-cmd.c @@ -0,0 +1,93 @@ +/* + This file is part of GNUnet + Copyright (C) 2008--2013, 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testbed/gnunet-cmd.c + * + * @brief Binary to start testcase plugins + * + * @author t3sserakt + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_lib.h" +#include "gnunet_testing_plugin.h" + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) + + +/** + * Handle for a plugin. + */ +struct Plugin +{ + /** + * Name of the shared library. + */ + char *library_name; + + /** + * Plugin API. + */ + struct GNUNET_TESTING_PluginFunctions *api; +}; + + +/** + * Main function to run the test cases. + * + * @param cls not used. + * + */ +static void +run (void *cls) +{ + struct Plugin *plugin; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "gnunet-cmd", + "running plugin.\n"); + LOG (GNUNET_ERROR_TYPE_ERROR, + "running plugin.\n"); + plugin = GNUNET_new (struct Plugin); + plugin->api = GNUNET_PLUGIN_load ("libgnunet_plugin_testcmd", + NULL); + plugin->library_name = GNUNET_strdup ("libgnunet_plugin_testcmd"); + plugin->api->start_testcase (); +} + + +int +main (int argc, char *const *argv) +{ + int rv = 0; + + GNUNET_log_setup ("gnunet-cmd", + "DEBUG", + NULL); + + GNUNET_SCHEDULER_run (&run, + NULL); + + return rv; +} diff --git a/src/testbed/gnunet-helper-cmds.c b/src/testbed/gnunet-helper-cmds.c new file mode 100644 index 000000000..3073ebdfb --- /dev/null +++ b/src/testbed/gnunet-helper-cmds.c @@ -0,0 +1,581 @@ +/* + This file is part of GNUnet + Copyright (C) 2008--2013, 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testbed/gnunet-helper-cmds.c + * @brief Helper binary that is started from a remote interpreter loop to start + * a local interpreter loop. + * + * This helper monitors for three termination events. They are: (1)The + * stdin of the helper is closed for reading; (2)the helper received + * SIGTERM/SIGINT; (3)the local loop crashed. In case of events 1 and 2 + * the helper kills the interpreter loop. When the interpreter loop + * crashed (event 3), the helper should send a SIGTERM to its own process + * group; this behaviour will help terminate any child processes the loop + * has started and prevents them from leaking and running forever. + * + * @author t3sserakt + * @author Sree Harsha Totakura + */ + + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_lib.h" +#include "gnunet_testbed_service.h" +#include "testbed_helper.h" +#include "testbed_api.h" +#include + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) + +/** + * Debug logging shorthand + */ +#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) + + +/** + * Context for a single write on a chunk of memory + */ +struct WriteContext +{ + /** + * The data to write + */ + void *data; + + /** + * The length of the data + */ + size_t length; + + /** + * The current position from where the write operation should begin + */ + size_t pos; +}; + +/** + * The process handle to the testbed service + */ +static struct GNUNET_OS_Process *cmd_binary_process; + +/** + * Handle to the testing system + */ +static struct GNUNET_TESTING_System *test_system; + +/** + * Our message stream tokenizer + */ +struct GNUNET_MessageStreamTokenizer *tokenizer; + +/** + * Disk handle from stdin + */ +static struct GNUNET_DISK_FileHandle *stdin_fd; + +/** + * Disk handle for stdout + */ +static struct GNUNET_DISK_FileHandle *stdout_fd; + +/** + * Pipe used to communicate shutdown via signal. + */ +static struct GNUNET_DISK_PipeHandle *sigpipe; + +/** + * Task identifier for the read task + */ +static struct GNUNET_SCHEDULER_Task *read_task_id; + +/** + * Task identifier for the write task + */ +static struct GNUNET_SCHEDULER_Task *write_task_id; + +/** + * Task to kill the child + */ +static struct GNUNET_SCHEDULER_Task *child_death_task_id; + +/** + * Are we done reading messages from stdin? + */ +static int done_reading; + +/** + * Result to return in case we fail + */ +static int status; + + +/** + * Task to shut down cleanly + * + * @param cls NULL + */ +static void +shutdown_task (void *cls) +{ + LOG_DEBUG ("Shutting down\n"); + + if (NULL != read_task_id) + { + GNUNET_SCHEDULER_cancel (read_task_id); + read_task_id = NULL; + } + if (NULL != write_task_id) + { + struct WriteContext *wc; + + wc = GNUNET_SCHEDULER_cancel (write_task_id); + write_task_id = NULL; + GNUNET_free (wc->data); + GNUNET_free (wc); + } + if (NULL != child_death_task_id) + { + GNUNET_SCHEDULER_cancel (child_death_task_id); + child_death_task_id = NULL; + } + if (NULL != stdin_fd) + (void) GNUNET_DISK_file_close (stdin_fd); + if (NULL != stdout_fd) + (void) GNUNET_DISK_file_close (stdout_fd); + GNUNET_MST_destroy (tokenizer); + tokenizer = NULL; + + if (NULL != test_system) + { + GNUNET_TESTING_system_destroy (test_system, GNUNET_YES); + test_system = NULL; + } +} + + +/** + * Task to write to the standard out + * + * @param cls the WriteContext + */ +static void +write_task (void *cls) +{ + struct WriteContext *wc = cls; + ssize_t bytes_wrote; + + GNUNET_assert (NULL != wc); + write_task_id = NULL; + bytes_wrote = GNUNET_DISK_file_write (stdout_fd, + wc->data + wc->pos, + wc->length - wc->pos); + if (GNUNET_SYSERR == bytes_wrote) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Cannot reply back configuration\n"); + GNUNET_free (wc->data); + GNUNET_free (wc); + return; + } + wc->pos += bytes_wrote; + if (wc->pos == wc->length) + { + GNUNET_free (wc->data); + GNUNET_free (wc); + return; + } + write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_fd, + &write_task, + wc); +} + + +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died). + * + * @param cls closure, NULL if we need to self-restart + */ +static void +child_death_task (void *cls) +{ + const struct GNUNET_DISK_FileHandle *pr; + char c[16]; + + pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); + child_death_task_id = NULL; + /* consume the signal */ + GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c))); + LOG_DEBUG ("Got SIGCHLD\n"); + + LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n"); + child_death_task_id = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + pr, + &child_death_task, + NULL); +} + + +/** + * Functions with this signature are called whenever a + * complete message is received by the tokenizer. + * + * Do not call #GNUNET_mst_destroy() in this callback + * + * @param cls identification of the client + * @param message the actual message + * @return #GNUNET_OK on success, + * #GNUNET_NO to stop further processing (no error) + * #GNUNET_SYSERR to stop further processing with error + */ +static int +tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TESTBED_HelperInit *msg; + struct GNUNET_TESTBED_HelperReply *reply; + struct GNUNET_CONFIGURATION_Handle *cfg; + struct WriteContext *wc; + char *binary; + char *trusted_ip; + char *hostname; + char *config; + char *xconfig; + char *evstr; + // char *str; + size_t config_size; + uLongf ul_config_size; + size_t xconfig_size; + uint16_t trusted_ip_size; + uint16_t hostname_size; + uint16_t msize; + + msize = ntohs (message->size); + if ((sizeof(struct GNUNET_TESTBED_HelperInit) >= msize) || + (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT != ntohs (message->type))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n"); + goto error; + } + msg = (const struct GNUNET_TESTBED_HelperInit *) message; + trusted_ip_size = ntohs (msg->trusted_ip_size); + trusted_ip = (char *) &msg[1]; + if ('\0' != trusted_ip[trusted_ip_size]) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Trusted IP cannot be empty -- exiting\n"); + goto error; + } + hostname_size = ntohs (msg->hostname_size); + if ((sizeof(struct GNUNET_TESTBED_HelperInit) + trusted_ip_size + 1 + + hostname_size) >= msize) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n"); + goto error; + } + ul_config_size = (uLongf) ntohs (msg->config_size); + config = GNUNET_malloc (ul_config_size); + xconfig_size = msize - (trusted_ip_size + 1 + hostname_size + + sizeof(struct GNUNET_TESTBED_HelperInit)); + int ret = uncompress ((Bytef *) config, + &ul_config_size, + (const Bytef *) (trusted_ip + trusted_ip_size + 1 + + hostname_size), + (uLongf) xconfig_size); + if (Z_OK != ret) + { + switch (ret) + { + case Z_MEM_ERROR: + LOG (GNUNET_ERROR_TYPE_ERROR, "Not enough memory for decompression\n"); + break; + + case Z_BUF_ERROR: + LOG (GNUNET_ERROR_TYPE_ERROR, "Output buffer too small\n"); + break; + + case Z_DATA_ERROR: + LOG (GNUNET_ERROR_TYPE_ERROR, "Data corrupted/incomplete\n"); + break; + + default: + GNUNET_break (0); + } + LOG (GNUNET_ERROR_TYPE_ERROR, + "Error while uncompressing config -- exiting\n"); + GNUNET_free (config); + goto error; + } + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_deserialize (cfg, config, ul_config_size, NULL)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to deserialize config -- exiting\n"); + GNUNET_free (config); + goto error; + } + GNUNET_free (config); + hostname = NULL; + if (0 != hostname_size) + { + hostname = GNUNET_malloc (hostname_size + 1); + GNUNET_strlcpy (hostname, + ((char *) &msg[1]) + trusted_ip_size + 1, + hostname_size + 1); + } + /* unset GNUNET_TESTING_PREFIX if present as it is more relevant for testbed */ + evstr = getenv (GNUNET_TESTING_PREFIX); + if (NULL != evstr) + { + /* unsetting the variable will invalidate the pointer! */ + evstr = GNUNET_strdup (evstr); + GNUNET_break (0 == unsetenv (GNUNET_TESTING_PREFIX)); + } + test_system = + GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname, NULL); + if (NULL != evstr) + { + char *evar; + + GNUNET_asprintf (&evar, GNUNET_TESTING_PREFIX "=%s", evstr); + GNUNET_assert (0 == putenv (evar)); /* consumes 'evar', + see putenv(): becomes part of environment! */ + GNUNET_free (evstr); + evstr = NULL; + } + GNUNET_free (hostname); + hostname = NULL; + GNUNET_assert (NULL != test_system); + GNUNET_assert (GNUNET_OK == + GNUNET_TESTING_configuration_create (test_system, cfg)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, + "PATHS", + "DEFAULTCONFIG", + &config)); + if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Unable to write config file: %s -- exiting\n", + config); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config); + goto error; + } + LOG_DEBUG ("Staring testbed with config: %s\n", config); + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd"); + { + char *evar; + + /* expose testbed configuration through env variable */ + GNUNET_asprintf (&evar, "%s=%s", ENV_TESTBED_CONFIG, config); + GNUNET_assert (0 == putenv (evar)); /* consumes 'evar', + see putenv(): becomes part of environment! */ + evstr = NULL; + } + + cmd_binary_process = GNUNET_OS_start_process ( + GNUNET_OS_INHERIT_STD_ERR /*verbose? */, + NULL, + NULL, + NULL, + binary); + + if (NULL == cmd_binary_process) + { + return GNUNET_SYSERR; + } + + GNUNET_free (binary); + GNUNET_free (config); + + done_reading = GNUNET_YES; + config = GNUNET_CONFIGURATION_serialize (cfg, &config_size); + GNUNET_CONFIGURATION_destroy (cfg); + cfg = NULL; + xconfig_size = + GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig); + GNUNET_free (config); + wc = GNUNET_new (struct WriteContext); + wc->length = xconfig_size + sizeof(struct GNUNET_TESTBED_HelperReply); + reply = GNUNET_realloc (xconfig, wc->length); + memmove (&reply[1], reply, xconfig_size); + reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY); + reply->header.size = htons ((uint16_t) wc->length); + reply->config_size = htons ((uint16_t) config_size); + wc->data = reply; + write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_fd, + &write_task, + wc); + child_death_task_id = GNUNET_SCHEDULER_add_read_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ), + &child_death_task, + NULL); + return GNUNET_OK; + + error: + status = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_SYSERR; +} + + +/** + * Task to read from stdin + * + * @param cls NULL + */ +static void +read_task (void *cls) +{ + char buf[GNUNET_MAX_MESSAGE_SIZE]; + ssize_t sread; + + read_task_id = NULL; + sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf)); + if ((GNUNET_SYSERR == sread) || (0 == sread)) + { + LOG_DEBUG ("STDIN closed\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_YES == done_reading) + { + /* didn't expect any more data! */ + GNUNET_break_op (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread); + /* FIXME: could introduce a GNUNET_MST_read2 to read + directly from 'stdin_fd' and save a memcpy() here */ + if (GNUNET_OK != + GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO)) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + read_task_id /* No timeout while reading */ + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdin_fd, + &read_task, + NULL); +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + LOG_DEBUG ("Starting interpreter loop helper...\n"); + tokenizer = GNUNET_MST_create (&tokenizer_cb, NULL); + stdin_fd = GNUNET_DISK_get_handle_from_native (stdin); + stdout_fd = GNUNET_DISK_get_handle_from_native (stdout); + read_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdin_fd, + &read_task, + NULL); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); +} + + +/** + * Signal handler called for SIGCHLD. + */ +static void +sighandler_child_death () +{ + static char c; + int old_errno; /* back-up errno */ + + old_errno = errno; + GNUNET_break ( + 1 == + GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_WRITE), + &c, + sizeof(c))); + errno = old_errno; +} + + +/** + * Main function + * + * @param argc the number of command line arguments + * @param argv command line arg array + * @return return code + */ +int +main (int argc, char **argv) +{ + struct GNUNET_SIGNAL_Context *shc_chld; + struct GNUNET_GETOPT_CommandLineOption options[] = + { GNUNET_GETOPT_OPTION_END }; + int ret; + + GNUNET_log_setup ("gnunet-helper-cmds", + "DEBUG", + NULL); + status = GNUNET_OK; + if (NULL == + (sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE))) + { + GNUNET_break (0); + return 1; + } + shc_chld = + GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); + ret = GNUNET_PROGRAM_run (argc, + argv, + "gnunet-helper-cmds", + "Helper for starting a local interpreter loop", + options, + &run, + NULL); + GNUNET_SIGNAL_handler_uninstall (shc_chld); + shc_chld = NULL; + GNUNET_DISK_pipe_close (sigpipe); + if (GNUNET_OK != ret) + return 1; + return (GNUNET_OK == status) ? 0 : 1; +} + + +/* end of gnunet-helper-testbed.c */ diff --git a/src/testbed/plugin_testcmd.c b/src/testbed/plugin_testcmd.c new file mode 100644 index 000000000..90e4a90a1 --- /dev/null +++ b/src/testbed/plugin_testcmd.c @@ -0,0 +1,87 @@ +/* + This file is part of GNUnet + Copyright (C) 2013, 2014 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testbed/plugin_testcmd.c + * @brief a plugin to provide the API for running test cases. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_plugin.h" + + + + + +static void +start_testcase () +{ + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + + struct GNUNET_TESTING_Command commands[] = { + GNUNET_TESTING_cmd_hello_world_birth ("hello-world-birth-0", + &now), + GNUNET_TESTING_cmd_hello_world ("hello-world-0","hello-world-birth-0",""), + GNUNET_TESTING_cmd_end () + }; + + GNUNET_TESTING_run (NULL, + commands, + GNUNET_TIME_UNIT_FOREVER_REL); + +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_testcmd_init (void *cls) +{ + struct GNUNET_TESTING_PluginFunctions *api; + + api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions); + api->start_testcase = &start_testcase; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init + * @return NULL + */ +void * +libgnunet_plugin_testcmd_done (void *cls) +{ + struct GNUNET_TESTING_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + + +/* end of plugin_gnsrecord_dns.c */ diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h index d4ef832ad..ea78a14ff 100644 --- a/src/testbed/testbed_api.h +++ b/src/testbed/testbed_api.h @@ -37,6 +37,11 @@ */ #define HELPER_TESTBED_BINARY "gnunet-helper-testbed" +/** + * Cmds Helper binary name + */ +#define HELPER_CMDS_BINARY "gnunet-helper-cmds" + /** * Enumeration of operations diff --git a/src/testbed/testbed_api_cmd_netjail_start_testbed.c b/src/testbed/testbed_api_cmd_netjail_start_testbed.c index 786084917..dc8196e94 100644 --- a/src/testbed/testbed_api_cmd_netjail_start_testbed.c +++ b/src/testbed/testbed_api_cmd_netjail_start_testbed.c @@ -248,7 +248,7 @@ start_testbed (struct NetJailState *ns, struct m_char, n_char, GNUNET_OS_get_libexec_binary_path ( - HELPER_TESTBED_BINARY), + HELPER_CMDS_BINARY), NULL}; unsigned int m = atoi (m_char); unsigned int n = atoi (n_char); @@ -285,9 +285,8 @@ start_testbed (struct NetJailState *ns, struct GNUNET_YES, NETJAIL_EXEC_SCRIPT, script_argv, - & - helper_mst, - exp_cb, + &helper_mst, + &exp_cb, tbc)); struct GNUNET_HELPER_Handle *helper = ns->helper[tbc->count - 1]; diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 82f6d0cab..49ed48063 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -204,6 +204,8 @@ run_finish_task_next (void *cls) } else { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Next task finished with an error.\n"); GNUNET_TESTING_interpreter_fail (); } @@ -246,6 +248,8 @@ run_finish_task_sync (void *cls) } else { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sync task finished with an error.\n"); GNUNET_TESTING_interpreter_fail (); } } @@ -325,16 +329,39 @@ GNUNET_TESTING_interpreter_fail () { struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed at command `%s'\n", - cmd->label); - while (GNUNET_TESTING_cmd_is_batch (cmd)) + if (GNUNET_SYSERR == is->result) + return; /* ignore, we already failed! */ + + if (NULL != cmd) + { + while (GNUNET_TESTING_cmd_is_batch (cmd)) + { + cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Batch is at command `%s'\n", + cmd->label); + } + + } + else { - cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Batch is at command `%s'\n", + "cmd is NULL.\n"); + } + + if (NULL == cmd->label) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed at command `%s'\n", cmd->label); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "cmd->label is NULL.\n"); + } + is->result = GNUNET_SYSERR; GNUNET_SCHEDULER_shutdown (); } @@ -386,7 +413,8 @@ interpreter_run (void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Running command END\n"); + "Running command END %p\n", + is); is->result = GNUNET_OK; GNUNET_SCHEDULER_shutdown (); return; @@ -394,8 +422,9 @@ interpreter_run (void *cls) else if (NULL != cmd) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Running command `%s'\n", - cmd->label); + "Running command `%s' %p\n", + cmd->label, + is); } cmd->start_time = cmd->last_req_time -- cgit v1.2.3