From 32a8c505c1fa27bb43c4e7c8d288566d51417f56 Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Tue, 17 Aug 2021 19:57:12 +0200 Subject: - moved test code from testbed to testing --- src/testing/Makefile.am | 41 ++ src/testing/gnunet-cmds-helper.c | 662 +++++++++++++++++++++ src/testing/test_testing_api_cmd_netjail.c | 79 +++ src/testing/test_testing_plugin_testcmd.c | 116 ++++ ...testing_api_cmd_block_until_all_peers_started.c | 128 ++++ src/testing/testing_api_cmd_local_test_finished.c | 131 ++++ src/testing/testing_api_cmd_netjail_start.c | 217 +++++++ .../testing_api_cmd_netjail_start_testsystem.c | 541 +++++++++++++++++ src/testing/testing_api_cmd_netjail_stop.c | 215 +++++++ .../testing_api_cmd_netjail_stop_testsystem.c | 141 +++++ src/testing/testing_api_cmd_send_peer_ready.c | 5 +- src/testing/testing_cmds.h | 90 +++ 12 files changed, 2363 insertions(+), 3 deletions(-) create mode 100644 src/testing/gnunet-cmds-helper.c create mode 100644 src/testing/test_testing_api_cmd_netjail.c create mode 100644 src/testing/test_testing_plugin_testcmd.c create mode 100644 src/testing/testing_api_cmd_block_until_all_peers_started.c create mode 100644 src/testing/testing_api_cmd_local_test_finished.c create mode 100644 src/testing/testing_api_cmd_netjail_start.c create mode 100644 src/testing/testing_api_cmd_netjail_start_testsystem.c create mode 100644 src/testing/testing_api_cmd_netjail_stop.c create mode 100644 src/testing/testing_api_cmd_netjail_stop_testsystem.c create mode 100644 src/testing/testing_cmds.h (limited to 'src/testing') diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 8b28e6e23..15469a310 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -11,10 +11,43 @@ pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testing.conf +libexec_PROGRAMS = \ + gnunet-cmds-helper + +plugindir = $(libdir)/gnunet + +plugin_LTLIBRARIES = \ + libgnunet_test_testing_plugin_testcmd.la + lib_LTLIBRARIES = \ libgnunettesting.la +gnunet_cmds_helper_SOURCES = \ + gnunet-cmds-helper.c +gnunet_cmds_helper_LDADD = $(XLIB) \ + $(top_builddir)/src/util/libgnunetutil.la \ + libgnunettesting.la \ + $(LTLIBINTL) $(Z_LIBS) + +libgnunet_test_testing_plugin_testcmd_la_SOURCES = \ + test_testing_plugin_testcmd.c +libgnunet_test_testing_plugin_testcmd_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + libgnunettesting.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(LTLIBINTL) +libgnunet_test_testing_plugin_testcmd_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + libgnunettesting_la_SOURCES = \ + testing_api_cmd_local_test_finished.c \ + testing_api_cmd_send_peer_ready.c \ + testing_api_cmd_block_until_all_peers_started.c \ + testing_api_cmd_netjail_start.c \ + testing_api_cmd_netjail_start_testsystem.c \ + testing_api_cmd_netjail_stop_testsystem.c \ + testing_api_cmd_netjail_stop.c \ testing.c testing.h \ testing_api_cmd_system_create.c \ testing_api_cmd_batch.c \ @@ -56,6 +89,7 @@ list_keys_LDADD = \ check_PROGRAMS = \ + test_testing_api_cmd_netjail \ test_testing_hello_world \ test_testing_portreservation \ test_testing_servicestartup \ @@ -66,6 +100,7 @@ check_PROGRAMS = \ if ENABLE_TEST_RUN AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; TESTS = \ + test_testing_api_cmd_netjail \ test_testing_hello_world \ test_testing_portreservation \ test_testing_peerstartup \ @@ -73,6 +108,12 @@ TESTS = \ test_testing_servicestartup endif +test_testing_api_cmd_netjail_SOURCES = \ + test_testing_api_cmd_netjail.c +test_testing_api_cmd_netjail_LDADD = \ + libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + test_testing_hello_world_SOURCES = \ test_testing_hello_world.c test_testing_hello_world_LDADD = \ diff --git a/src/testing/gnunet-cmds-helper.c b/src/testing/gnunet-cmds-helper.c new file mode 100644 index 000000000..d9fcf3541 --- /dev/null +++ b/src/testing/gnunet-cmds-helper.c @@ -0,0 +1,662 @@ +/* + 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-cmds-helper.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_testing_ng_lib.h" +#include "testing_cmds.h" +#include "gnunet_testing_plugin.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__) + +#define NODE_BASE_IP "192.168.15." + +#define ROUTER_BASE_IP "92.68.150." + +/** + * Handle for a plugin. + */ +struct Plugin +{ + /** + * Name of the shared library. + */ + char *library_name; + + /** + * Plugin API. + */ + struct GNUNET_TESTING_PluginFunctions *api; + + char *node_ip; + + char *plugin_name; + + char *global_n; + + char *local_m; + + char *n; + + char *m; +}; + +struct NodeIdentifier +{ + char *n; + + char *m; + + char *global_n; + + char *local_m; +}; + +/** + * 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; +}; + +struct Plugin *plugin; + +/** + * 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"); + LOG (GNUNET_ERROR_TYPE_ERROR, + "Shutting down tokenizer!\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; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "Writing data!\n"); + + 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 successful initialization\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); + LOG (GNUNET_ERROR_TYPE_ERROR, + "Written successfully!\n"); + return; + } + LOG (GNUNET_ERROR_TYPE_ERROR, + "Written data!\n"); + 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); +}*/ + + +static void +write_message (struct GNUNET_MessageHeader *message, size_t msg_length) +{ + struct WriteContext *wc; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "enter write_message!\n"); + wc = GNUNET_new (struct WriteContext); + wc->length = msg_length; + wc->data = message; + write_task_id = GNUNET_SCHEDULER_add_write_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + stdout_fd, + &write_task, + wc); + LOG (GNUNET_ERROR_TYPE_ERROR, + "leave write_message!\n"); +} + + +/** + * Function to run the test cases. + * + * @param cls plugin to use. + * + */ +/*static void +run_plugin (void *cls) +{ + struct Plugin *plugin = cls; + char *router_ip; + char *node_ip; + + router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m) + 1); + strcpy (router_ip, ROUTER_BASE_IP); + strcat (router_ip, plugin->m); + + node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1); + strcat (node_ip, NODE_BASE_IP); + strcat (node_ip, plugin->n); + + plugin->api->start_testcase (&write_message, router_ip, node_ip); + +}*/ + + +/** + * 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) +{ + struct NodeIdentifier *ni = cls; + const struct GNUNET_CMDS_HelperInit *msg; + struct GNUNET_CMDS_HelperReply *reply; + char *binary; + char *plugin_name; + size_t plugin_name_size; + uint16_t msize; + size_t msg_length; + char *router_ip; + char *node_ip; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "tokenizer \n"); + + msize = ntohs (message->size); + if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type)) + { + msg = (const struct GNUNET_CMDS_HelperInit *) message; + plugin_name_size = ntohs (msg->plugin_name_size); + if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Received unexpected message -- exiting\n"); + goto error; + } + plugin_name = GNUNET_malloc (plugin_name_size + 1); + GNUNET_strlcpy (plugin_name, + ((char *) &msg[1]), + plugin_name_size + 1); + + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd"); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "plugin_name: %s \n", + plugin_name); + + // cmd_binary_process = GNUNET_OS_start_process ( + /*GNUNET_OS_INHERIT_STD_ERR verbose? , + NULL, + NULL, + NULL, + binary, + plugin_name, + ni->global_n, + ni->local_m, + ni->n, + ni->m, + NULL);*/ + + plugin = GNUNET_new (struct Plugin); + plugin->api = GNUNET_PLUGIN_load (plugin_name, + NULL); + plugin->library_name = GNUNET_strdup (basename (plugin_name)); + + plugin->global_n = ni->global_n; + plugin->local_m = ni->local_m; + plugin->n = ni->n; + plugin->m = ni->m; + + router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m) + + 1); + strcpy (router_ip, ROUTER_BASE_IP); + strcat (router_ip, plugin->m); + + node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1); + strcat (node_ip, NODE_BASE_IP); + strcat (node_ip, plugin->n); + + plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m, + plugin->n, plugin->local_m); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here!\n"); + + /*if (NULL == cmd_binary_process) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Starting plugin failed!\n"); + return GNUNET_SYSERR; + }*/ + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 2!\n"); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "global_n: %s local_n: %s n: %s m: %s.\n", + ni->global_n, + ni->local_m, + ni->n, + ni->m); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 3!\n"); + + GNUNET_free (binary); + + // done_reading = GNUNET_YES; + + msg_length = sizeof(struct GNUNET_CMDS_HelperReply); + reply = GNUNET_new (struct GNUNET_CMDS_HelperReply); + reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY); + reply->header.size = htons ((uint16_t) msg_length); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 4!\n"); + + write_message ((struct GNUNET_MessageHeader *) reply, msg_length); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 5!\n"); + + /*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; + } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED == ntohs ( + message->type)) + { + plugin->api->all_peers_started (); + return GNUNET_OK; + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n"); + goto error; + } + + + error: + status = GNUNET_SYSERR; + LOG (GNUNET_ERROR_TYPE_ERROR, + "tokenizer shutting down!\n"); + 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"); + LOG (GNUNET_ERROR_TYPE_ERROR, + "tokenizer shutting down during reading!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_YES == done_reading) + { + /* didn't expect any more data! */ + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_ERROR, + "tokenizer shutting down during reading, didn't expect any more data!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread); + LOG (GNUNET_ERROR_TYPE_ERROR, + "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); + LOG (GNUNET_ERROR_TYPE_ERROR, + "tokenizer shutting down during reading, writing to buffer failed!\n"); + 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) +{ + struct NodeIdentifier *ni = cls; + + LOG_DEBUG ("Starting interpreter loop helper...\n"); + + tokenizer = GNUNET_MST_create (&tokenizer_cb, ni); + 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 NodeIdentifier *ni; + struct GNUNET_SIGNAL_Context *shc_chld; + struct GNUNET_GETOPT_CommandLineOption options[] = + { GNUNET_GETOPT_OPTION_END }; + int ret; + + GNUNET_log_setup ("gnunet-cmds-helper", + "DEBUG", + NULL); + ni = GNUNET_new (struct NodeIdentifier); + ni->global_n = argv[1]; + ni->local_m = argv[2]; + ni->n = argv[3]; + ni->m = argv[4]; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "global_n: %s local_n: %s n: %s m: %s.\n", + ni->global_n, + ni->local_m, + ni->n, + ni->m); + + 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-cmds-helper", + "Helper for starting a local interpreter loop", + options, + &run, + ni); + LOG (GNUNET_ERROR_TYPE_ERROR, + "run finished\n"); + GNUNET_SIGNAL_handler_uninstall (shc_chld); + shc_chld = NULL; + GNUNET_DISK_pipe_close (sigpipe); + GNUNET_free (ni); + if (GNUNET_OK != ret) + return 1; + return (GNUNET_OK == status) ? 0 : 1; +} + + +/* end of gnunet-cmds-helper.c */ diff --git a/src/testing/test_testing_api_cmd_netjail.c b/src/testing/test_testing_api_cmd_netjail.c new file mode 100644 index 000000000..543642109 --- /dev/null +++ b/src/testing/test_testing_api_cmd_netjail.c @@ -0,0 +1,79 @@ +/* + 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 + */ + +/** + * @file testing/test_testbed_api_cmd_netjail.c + * @brief Test case executing a script in a network name space. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "gnunet_util_lib.h" + + +/** + * Main function to run the test cases. + * + * @param cls not used. + * + */ +static void +run (void *cls) +{ + struct GNUNET_TESTING_Command commands[] = { + GNUNET_TESTING_cmd_netjail_start ("netjail-start-1", + "2", + "2"), + GNUNET_TESTING_cmd_netjail_start_testing_system ("netjail-start-testbed-1", + "2", + "2", + "libgnunet_plugin_testcmd"), + GNUNET_TESTING_cmd_stop_testing_system ("stop-testbed", + "netjail-start-testbed-1", + "2", + "2"), + GNUNET_TESTING_cmd_netjail_stop ("netjail-stop-1", + "2", + "2"), + GNUNET_TESTING_cmd_end () + }; + + GNUNET_TESTING_run (NULL, + commands, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +int +main (int argc, + char *const *argv) +{ + int rv = 0; + + GNUNET_log_setup ("test-netjail", + "DEBUG", + NULL); + GNUNET_SCHEDULER_run (&run, + NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test finished!\n"); + return rv; +} diff --git a/src/testing/test_testing_plugin_testcmd.c b/src/testing/test_testing_plugin_testcmd.c new file mode 100644 index 000000000..aeb0db5dc --- /dev/null +++ b/src/testing/test_testing_plugin_testcmd.c @@ -0,0 +1,116 @@ +/* + 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_ng_lib.h" + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) + +unsigned int are_all_peers_started; + +static void +all_peers_started () +{ + are_all_peers_started = GNUNET_YES; + LOG (GNUNET_ERROR_TYPE_ERROR, + "setting are_all_peers_started: %d\n", + are_all_peers_started); +} + +static void +start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip, + char *node_ip, + char *n, + char *m, + char *local_m) +{ + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 6!\n"); + + are_all_peers_started = GNUNET_NO; + + 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_send_peer_ready ("send-peer-ready-1", + write_message), + GNUNET_TESTING_cmd_block_until_all_peers_started ("block-1", + &are_all_peers_started), + GNUNET_TESTING_cmd_local_test_finished ("local-test-finished-1", + write_message) + }; + + GNUNET_TESTING_run (NULL, + commands, + GNUNET_TIME_UNIT_FOREVER_REL); + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 7!\n"); + +} + + +/** + * 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; + api->all_peers_started = &all_peers_started; + 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_testcmd.c */ diff --git a/src/testing/testing_api_cmd_block_until_all_peers_started.c b/src/testing/testing_api_cmd_block_until_all_peers_started.c new file mode 100644 index 000000000..8659fbb46 --- /dev/null +++ b/src/testing/testing_api_cmd_block_until_all_peers_started.c @@ -0,0 +1,128 @@ +/* + 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 + */ + +/** + * @file testing_api_cmd_block_until_all_peers_started.c + * @brief cmd to block the interpreter loop until all peers started. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) + +struct BlockState +{ + unsigned int *all_peers_started; +}; + + +static int +block_until_all_peers_started_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +static void +block_until_all_peers_started_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct BlockState *bs = cls; + + GNUNET_free (bs); +} + + +static void +block_until_all_peers_started_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + LOG (GNUNET_ERROR_TYPE_ERROR, + "block_until_all_peers_started_run!\n"); +} + + +static int +block_until_all_peers_started_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + struct BlockState *bs = cls; + unsigned int *ret = bs->all_peers_started; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 10\n"); + + if (GNUNET_YES == *ret) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "We do not need to block anymore!\n"); + cont (cont_cls); + } + else + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "You shall not pass!\n"); + } + + return *ret; +} + + +/** + * Create command. + * + * @param label name for command. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_block_until_all_peers_started (const char *label, + unsigned int * + all_peers_started) +{ + struct BlockState *bs; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "we have all_peers_started: %u\n", + *all_peers_started); + + bs = GNUNET_new (struct BlockState); + bs->all_peers_started = all_peers_started; + + struct GNUNET_TESTING_Command cmd = { + .cls = bs, + .label = label, + .run = &block_until_all_peers_started_run, + .finish = &block_until_all_peers_started_finish, + .cleanup = &block_until_all_peers_started_cleanup, + .traits = &block_until_all_peers_started_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_local_test_finished.c b/src/testing/testing_api_cmd_local_test_finished.c new file mode 100644 index 000000000..5b74d4e04 --- /dev/null +++ b/src/testing/testing_api_cmd_local_test_finished.c @@ -0,0 +1,131 @@ +/* + 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 + */ + +/** + * @file testing_api_cmd_block_until_all_peers_started.c + * @brief cmd to block the interpreter loop until all peers started. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" +#include "testing_cmds.h" + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) + +struct LocalFinishedState +{ + TESTING_CMD_HELPER_write_cb write_message; + + struct GNUNET_CMDS_LOCAL_FINISHED *reply; +}; + + +static int +local_test_finished_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +static void +local_test_finished_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct LocalFinishedState *lfs = cls; + + GNUNET_free (lfs->reply); + GNUNET_free (lfs); +} + + +static void +local_test_finished_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct LocalFinishedState *lfs = cls; + + struct GNUNET_CMDS_LOCAL_FINISHED *reply; + size_t msg_length; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 12!\n"); + + msg_length = sizeof(struct GNUNET_CMDS_LOCAL_FINISHED); + reply = GNUNET_new (struct GNUNET_CMDS_LOCAL_FINISHED); + reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED); + reply->header.size = htons ((uint16_t) msg_length); + lfs->reply = reply; + lfs->write_message ((struct GNUNET_MessageHeader *) reply, msg_length); + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 13!\n"); +} + + +static int +local_test_finished_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + // This will stop the local loop without shutting down the scheduler, because we do not call the continuation, which is the interpreter_next method. + LOG (GNUNET_ERROR_TYPE_ERROR, + "Stopping local loop\n"); + return GNUNET_YES; +} + + +/** + * Create command. + * + * @param label name for command. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_local_test_finished (const char *label, + TESTING_CMD_HELPER_write_cb + write_message) +{ + struct LocalFinishedState *lfs; + + LOG (GNUNET_ERROR_TYPE_ERROR, + "We got here 11!\n"); + + lfs = GNUNET_new (struct LocalFinishedState); + lfs->write_message = write_message; + + struct GNUNET_TESTING_Command cmd = { + .cls = lfs, + .label = label, + .run = &local_test_finished_run, + .finish = &local_test_finished_finish, + .cleanup = &local_test_finished_cleanup, + .traits = &local_test_finished_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_start.c b/src/testing/testing_api_cmd_netjail_start.c new file mode 100644 index 000000000..c82392a08 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_start.c @@ -0,0 +1,217 @@ +/* + 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 + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail script. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" + +#define NETJAIL_START_SCRIPT "./../testing/netjail_start.sh" + +struct NetJailState +{ + struct GNUNET_ChildWaitHandle *cwh; + + char *local_m; + + char *global_n; + + /** + * The process id of the start script. + */ + struct GNUNET_OS_Process *start_proc; + + unsigned int finished; +}; + + +/** +* +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +netjail_start_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "netjail_start_cleanup!\n"); + + if (NULL != ns->cwh) + { + GNUNET_wait_child_cancel (ns->cwh); + ns->cwh = NULL; + } + if (NULL != ns->start_proc) + { + GNUNET_assert (0 == + GNUNET_OS_process_kill (ns->start_proc, + SIGKILL)); + GNUNET_assert (GNUNET_OK == + GNUNET_OS_process_wait (ns->start_proc)); + GNUNET_OS_process_destroy (ns->start_proc); + ns->start_proc = NULL; + } + GNUNET_free (ns); +} + + +/** +* +* +* @param cls closure. +* @param[out] ret result +* @param trait name of the trait. +* @param index index number of the object to offer. +* @return #GNUNET_OK on success. +*/ +static int +netjail_start_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + +static void +child_completed_callback (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct NetJailState *ns = cls; + + if (0 == exit_code) + { + ns->finished = GNUNET_YES; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Child completed with an error!\n"); + ns->finished = GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (ns->start_proc); + ns->start_proc = NULL; +} + + + +/** +* Run the "hello world" CMD. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_start_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct NetJailState *ns = cls; + char *const script_argv[] = {NETJAIL_START_SCRIPT, + ns->local_m, + ns->global_n, + NULL}; + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_START_SCRIPT, + GNUNET_YES, + NULL); + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_START_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_START_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + + ns->start_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR, + NULL, + NULL, + NULL, + NETJAIL_START_SCRIPT, + script_argv); + + ns->cwh = GNUNET_wait_child (ns->start_proc, + &child_completed_callback, + ns); + GNUNET_break (NULL != ns->cwh); +} + +static int +netjail_start_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + struct NetJailState *ns = cls; + + if (ns->finished) + { + cont (cont_cls); + } + return ns->finished; +} + +/** + * Create command. + * + * @param label name for command. + * @param binaryname to start. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_start (const char *label, + char *local_m, + char *global_n) +{ + struct NetJailState *ns; + + ns = GNUNET_new (struct NetJailState); + ns->local_m = local_m; + ns->global_n = global_n; + ns->finished = GNUNET_NO; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_start_run, + .finish = &netjail_start_finish, + .cleanup = &netjail_start_cleanup, + .traits = &netjail_start_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_start_testsystem.c b/src/testing/testing_api_cmd_netjail_start_testsystem.c new file mode 100644 index 000000000..5c2f71168 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_start_testsystem.c @@ -0,0 +1,541 @@ +/* + 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 + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail peers. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "testing_cmds.h" + +#define NETJAIL_EXEC_SCRIPT "./../testing/netjail_exec.sh" + +struct HelperMessage; + +struct HelperMessage +{ + + struct HelperMessage *next; + + struct HelperMessage *prev; + + /** + * Size of the original message. + */ + uint16_t bytes_msg; + + /* Followed by @e bytes_msg of msg.*/ +}; + + + +struct NetJailState +{ + + unsigned int *rv; + + struct HelperMessage *hp_messages_head; + + struct HelperMessage *hp_messages_tail; + + /** + * The process handle + */ + struct GNUNET_HELPER_Handle **helper; + + unsigned int n_helper; + + char *binary_name; + + char *local_m; + + char *global_n; + + /** + * The send handle for the helper + */ + struct GNUNET_HELPER_SendHandle **shandle; + + unsigned int n_shandle; + + /** + * The message corresponding to send handle + */ + struct GNUNET_MessageHeader **msg; + + unsigned int n_msg; + + unsigned int number_of_testsystems_started; + + unsigned int number_of_peers_started; + + unsigned int number_of_local_test_finished; + + char *plugin_name; +}; + +struct TestingSystemCount +{ + unsigned int count; + + struct NetJailState *ns; +}; + +/** +* +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +netjail_exec_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + + GNUNET_free (ns->binary_name); +} + + +/** +* +* +* @param cls closure. +* @param[out] ret result +* @param trait name of the trait. +* @param index index number of the object to offer. +* @return #GNUNET_OK on success. +*/ +static int +netjail_exec_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct NetJailState *ns = cls; + struct GNUNET_HELPER_Handle **helper = ns->helper; + struct HelperMessage *hp_messages_head = ns->hp_messages_head; + + + struct GNUNET_TESTING_Trait traits[] = { + { + .index = 0, + .trait_name = "helper_handles", + .ptr = (const void *) helper, + }, + { + .index = 1, + .trait_name = "hp_msgs_head", + .ptr = (const void *) hp_messages_head, + }, + GNUNET_TESTING_trait_end () + }; + + return GNUNET_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Offer handles to testing cmd helper from trait + * + * @param cmd command to extract the message from. + * @param pt pointer to message. + * @return #GNUNET_OK on success. + */ +int +GNUNET_TESTING_get_trait_helper_handles (const struct + GNUNET_TESTING_Command *cmd, + struct GNUNET_HELPER_Handle ***helper) +{ + return cmd->traits (cmd->cls, + (const void **) helper, + "helper_handles", + (unsigned int) 0); +} + +/** + * Offer messages received via testing cmd helper from trait + * + * @param cmd command to extract the message from. + * @param pt pointer to message. + * @return #GNUNET_OK on success. + */ +int +GNUNET_TESTING_get_trait_helper_messages (const struct + GNUNET_TESTING_Command *cmd, + struct HelperMessage *** + hp_messages_head) +{ + return cmd->traits (cmd->cls, + (const void **) hp_messages_head, + "hp_msgs_head", + (unsigned int) 1); +} + + +/** + * Continuation function from GNUNET_HELPER_send() + * + * @param cls closure + * @param result GNUNET_OK on success, + * GNUNET_NO if helper process died + * GNUNET_SYSERR during GNUNET_HELPER_stop + */ +static void +clear_msg (void *cls, int result) +{ + struct TestingSystemCount *tbc = cls; + struct NetJailState *ns = tbc->ns; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "clear_msg tbc->count: %d\n", + tbc->count); + GNUNET_assert (NULL != ns->shandle[tbc->count - 1]); + ns->shandle[tbc->count - 1] = NULL; + GNUNET_free (ns->msg[tbc->count - 1]); + ns->msg[tbc->count - 1] = NULL; +} + + +/** + * Functions with this signature are called whenever a + * complete message is received by the tokenizer. + * + * Do not call GNUNET_SERVER_mst_destroy in callback + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + * + * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing + */ +static int +helper_mst (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct TestingSystemCount *tbc = cls; + struct NetJailState *ns = tbc->ns; + struct HelperMessage *hp_msg; + + if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY == ntohs (message->type)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "helper_mst tbc->count: %d\n", + tbc->count); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from helper.\n"); + ns->number_of_testsystems_started++; + } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED == ntohs ( + message->type)) + { + ns->number_of_peers_started++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "number_of_peers_started: %d\n", + ns->number_of_peers_started); + } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED == ntohs ( + message->type)) + { + ns->number_of_local_test_finished++; + } + else + { + hp_msg = GNUNET_new (struct HelperMessage); + hp_msg->bytes_msg = message->size; + memcpy (&hp_msg[1], message, message->size); + GNUNET_CONTAINER_DLL_insert (ns->hp_messages_head, ns->hp_messages_tail, + hp_msg); + } + + return GNUNET_OK; +} + + +static void +exp_cb (void *cls) +{ + struct NetJailState *ns = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n"); + *ns->rv = 1; +} + + +static struct GNUNET_CMDS_HelperInit * +create_helper_init_msg_ (char *m_char, + char *n_char, + const char *plugin_name) +{ + struct GNUNET_CMDS_HelperInit *msg; + uint16_t plugin_name_len; + uint16_t msg_size; + + GNUNET_assert (NULL != plugin_name); + plugin_name_len = strlen (plugin_name); + msg_size = sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_len; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "msg_size: %d \n", + msg_size); + msg = GNUNET_malloc (msg_size); + msg->header.size = htons (msg_size); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT); + msg->plugin_name_size = htons (plugin_name_len); + GNUNET_memcpy ((char *) &msg[1], + plugin_name, + plugin_name_len); + return msg; +} + + +static void +start_helper (struct NetJailState *ns, struct + GNUNET_CONFIGURATION_Handle *config, + char *m_char, + char *n_char) +{ + // struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CMDS_HelperInit *msg; + struct TestingSystemCount *tbc; + char *const script_argv[] = {NETJAIL_EXEC_SCRIPT, + m_char, + n_char, + GNUNET_OS_get_libexec_binary_path ( + HELPER_CMDS_BINARY), + ns->global_n, + ns->local_m, + NULL}; + unsigned int m = atoi (m_char); + unsigned int n = atoi (n_char); + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_EXEC_SCRIPT, + GNUNET_YES, + NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "m: %d n: %d\n", + m, + n); + + tbc = GNUNET_new (struct TestingSystemCount); + tbc->ns = ns; + tbc->count = (n - 1) * atoi (ns->local_m) + m; + + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_EXEC_SCRIPT); + *ns->rv = 1; + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_EXEC_SCRIPT); + *ns->rv = 1; + } + + GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start ( + GNUNET_YES, + NETJAIL_EXEC_SCRIPT, + script_argv, + &helper_mst, + &exp_cb, + tbc)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "First using helper %d %d\n", + tbc->count - 1, + ns->n_helper); + struct GNUNET_HELPER_Handle *helper = ns->helper[tbc->count - 1]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "First using helper %d %d %p\n", + tbc->count - 1, + ns->n_helper, + helper); + + msg = create_helper_init_msg_ (m_char, + n_char, + ns->plugin_name); + GNUNET_array_append (ns->msg, ns->n_msg, &msg->header); + + GNUNET_array_append (ns->shandle, ns->n_shandle, GNUNET_HELPER_send ( + helper, + &msg->header, + GNUNET_NO, + &clear_msg, + tbc)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Message %d send!\n", + tbc->count); + + if (NULL == ns->shandle[tbc->count - 1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Send handle is NULL!\n"); + GNUNET_free (msg); + *ns->rv = 1; + } +} + + +/** +* Run the "hello world" CMD. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_exec_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + char str_m[12]; + char str_n[12]; + struct NetJailState *ns = cls; + struct GNUNET_CONFIGURATION_Handle *config = + GNUNET_CONFIGURATION_create (); + + for (int i = 1; i <= atoi (ns->global_n); i++) { + for (int j = 1; j <= atoi (ns->local_m); j++) + { + sprintf (str_n, "%d", i); + sprintf (str_m, "%d", j); + start_helper (ns, config, + str_m, + str_n); + } + } +} + + +static int +netjail_start_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + unsigned int ret = GNUNET_NO; + struct NetJailState *ns = cls; + unsigned int total_number = atoi (ns->local_m) * atoi (ns->global_n); + struct GNUNET_CMDS_ALL_PEERS_STARTED *reply; + size_t msg_length; + struct GNUNET_HELPER_Handle *helper; + struct TestingSystemCount *tbc; + + if (ns->number_of_local_test_finished == total_number) + { + ret = GNUNET_YES; + cont (cont_cls); + } + + if (ns->number_of_testsystems_started == total_number) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All helpers started!\n"); + ns->number_of_testsystems_started = 0; + } + + if (ns->number_of_peers_started == total_number) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers started!\n"); + + for (int i = 1; i <= atoi (ns->global_n); i++) { + for (int j = 1; j <= atoi (ns->local_m); j++) + { + tbc = GNUNET_new (struct TestingSystemCount); + tbc->ns = ns; + // TODO This needs to be more generic. As we send more messages back and forth, we can not grow the arrays again and again, because this is to error prone. + tbc->count = (i - 1) * atoi (ns->local_m) + j + total_number; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Second using helper %d %d %d\n", + tbc->count - 1 - total_number, + i, + j); + helper = ns->helper[tbc->count - 1 - total_number]; + msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED); + reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED); + reply->header.type = htons ( + GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED); + reply->header.size = htons ((uint16_t) msg_length); + + GNUNET_array_append (ns->msg, ns->n_msg, &reply->header); + + struct GNUNET_HELPER_SendHandle *sh = GNUNET_HELPER_send ( + helper, + &reply->header, + GNUNET_NO, + &clear_msg, + tbc); + + GNUNET_array_append (ns->shandle, ns->n_shandle, sh); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers started message %d send!\n", + tbc->count); + } + } + ns->number_of_peers_started = 0; + } + return ret; +} + + +/** + * Create command. + * + * @param label name for command. + * @param binaryname to exec. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_start_testing_system (const char *label, + char *local_m, + char *global_n, + char *plugin_name, + unsigned int *rv) +{ + struct NetJailState *ns; + + ns = GNUNET_new (struct NetJailState); + ns->local_m = local_m; + ns->global_n = global_n; + ns->plugin_name = plugin_name; + ns->rv = rv; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_exec_run, + .finish = &netjail_start_finish, + .cleanup = &netjail_exec_cleanup, + .traits = &netjail_exec_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_stop.c b/src/testing/testing_api_cmd_netjail_stop.c new file mode 100644 index 000000000..710b4fbf4 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_stop.c @@ -0,0 +1,215 @@ +/* + 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 + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to stop the netjail script. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" + + +#define NETJAIL_STOP_SCRIPT "./../testing/netjail_stop.sh" + +struct GNUNET_ChildWaitHandle *cwh; + +struct NetJailState +{ + char *local_m; + + char *global_n; + + /** + * The process id of the start script. + */ + struct GNUNET_OS_Process *stop_proc; + + unsigned int finished; +}; + + +/** +* +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +netjail_stop_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + + if (NULL != cwh) + { + GNUNET_wait_child_cancel (cwh); + cwh = NULL; + } + if (NULL != ns->stop_proc) + { + GNUNET_assert (0 == + GNUNET_OS_process_kill (ns->stop_proc, + SIGKILL)); + GNUNET_assert (GNUNET_OK == + GNUNET_OS_process_wait (ns->stop_proc)); + GNUNET_OS_process_destroy (ns->stop_proc); + ns->stop_proc = NULL; + } +} + + +/** +* +* +* @param cls closure. +* @param[out] ret result +* @param trait name of the trait. +* @param index index number of the object to offer. +* @return #GNUNET_OK on success. +*/ +static int +netjail_stop_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +static void +child_completed_callback (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct NetJailState *ns = cls; + + cwh = NULL; + if (0 == exit_code) + { + ns->finished = GNUNET_YES; + } + else + { + ns->finished = GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (ns->stop_proc); + ns->stop_proc = NULL; +} + + +/** +* Run the "hello world" CMD. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_stop_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct NetJailState *ns = cls; + char *const script_argv[] = {NETJAIL_STOP_SCRIPT, + ns->local_m, + ns->global_n, + NULL}; + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_STOP_SCRIPT, + GNUNET_YES, + NULL); + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_STOP_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_STOP_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + + ns->stop_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR, + NULL, + NULL, + NULL, + NETJAIL_STOP_SCRIPT, + script_argv); + + cwh = GNUNET_wait_child (ns->stop_proc, + &child_completed_callback, + ns); + GNUNET_break (NULL != cwh); + +} + + +static int +netjail_stop_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + struct NetJailState *ns = cls; + + if (ns->finished) + { + cont (cont_cls); + } + return ns->finished; +} + + +/** + * Create command. + * + * @param label name for command. + * @param binaryname to stop. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_stop (const char *label, + char *local_m, + char *global_n) +{ + struct NetJailState *ns; + + ns = GNUNET_new (struct NetJailState); + ns->local_m = local_m; + ns->global_n = global_n; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_stop_run, + .finish = &netjail_stop_finish, + .cleanup = &netjail_stop_cleanup, + .traits = &netjail_stop_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_stop_testsystem.c b/src/testing/testing_api_cmd_netjail_stop_testsystem.c new file mode 100644 index 000000000..bed9f3ebf --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_stop_testsystem.c @@ -0,0 +1,141 @@ +/* + 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 + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail peers. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "testing_cmds.h" + + +struct StopHelperState +{ + + const char *helper_start_label; + + /** + * The process handle + */ + struct GNUNET_HELPER_Handle **helper; + + char *local_m; + + char *global_n; +}; + + +/** +* +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +stop_testing_system_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + +} + + +/** +* +* +* @param cls closure. +* @param[out] ret result +* @param trait name of the trait. +* @param index index number of the object to offer. +* @return #GNUNET_OK on success. +*/ +static int +stop_testing_system_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +/** +* Run the "hello world" CMD. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +stop_testing_system_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct StopHelperState *shs = cls; + struct GNUNET_HELPER_Handle **helper; + const struct GNUNET_TESTING_Command *start_helper_cmd; + + start_helper_cmd = GNUNET_TESTING_interpreter_lookup_command ( + shs->helper_start_label); + GNUNET_TESTING_get_trait_helper_handles (start_helper_cmd, + &helper); + + for (int i = 1; i <= atoi (shs->global_n); i++) { + for (int j = 1; j <= atoi (shs->local_m); j++) + { + GNUNET_HELPER_stop (helper[(i - 1) * atoi (shs->local_m) + j - 1], + GNUNET_YES); + } + } +} + + +/** + * Create command. + * + * @param label name for command. + * @param binaryname to exec. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_stop_testing_system (const char *label, + const char *helper_start_label, + char *local_m, + char *global_n + ) +{ + struct StopHelperState *shs; + + shs = GNUNET_new (struct StopHelperState); + shs->helper_start_label = helper_start_label; + shs->local_m = local_m; + shs->global_n = global_n; + + struct GNUNET_TESTING_Command cmd = { + .cls = shs, + .label = label, + .run = &stop_testing_system_run, + .cleanup = &stop_testing_system_cleanup, + .traits = &stop_testing_system_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_send_peer_ready.c b/src/testing/testing_api_cmd_send_peer_ready.c index e5e004924..afe28de77 100644 --- a/src/testing/testing_api_cmd_send_peer_ready.c +++ b/src/testing/testing_api_cmd_send_peer_ready.c @@ -26,8 +26,7 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_testing_ng_lib.h" -#include "testbed_api.h" -#include "testbed_helper.h" +#include "testing_cmds.h" struct SendPeerReadyState @@ -68,7 +67,7 @@ send_peer_ready_run (void *cls, struct GNUNET_CMDS_PEER_STARTED *reply; size_t msg_length; - msg_length = sizeof(struct GNUNET_CMDS_HelperInit);// GNUNET_CMDS_PEER_STARTED); + msg_length = sizeof(struct GNUNET_CMDS_PEER_STARTED); reply = GNUNET_new (struct GNUNET_CMDS_PEER_STARTED); reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED); reply->header.size = htons ((uint16_t) msg_length); diff --git a/src/testing/testing_cmds.h b/src/testing/testing_cmds.h new file mode 100644 index 000000000..7a5860aea --- /dev/null +++ b/src/testing/testing_cmds.h @@ -0,0 +1,90 @@ +/* + 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 + */ + +/** + * @file testing/testing_cmds.h + * @brief Message formats for communication between testing cmds helper and testcase plugins. + * @author t3sserakt + */ + +#ifndef TESTING_CMDS_H +#define TESTING_CMDS_H + +#define HELPER_CMDS_BINARY "gnunet-cmds-helper" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Initialization message for gnunet-cmds-testbed to start cmd binary. + */ +struct GNUNET_CMDS_HelperInit +{ + /** + * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT + */ + struct GNUNET_MessageHeader header; + + /** + * + */ + uint16_t plugin_name_size GNUNET_PACKED; + + /* Followed by plugin name of the plugin running the test case. This is not NULL + * terminated */ +}; + +/** + * Reply message from cmds helper process + */ +struct GNUNET_CMDS_HelperReply +{ + /** + * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY + */ + struct GNUNET_MessageHeader header; +}; + +struct GNUNET_CMDS_PEER_STARTED +{ + /** + * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED + */ + struct GNUNET_MessageHeader header; +}; + +struct GNUNET_CMDS_ALL_PEERS_STARTED +{ + /** + * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED + */ + struct GNUNET_MessageHeader header; +}; + +struct GNUNET_CMDS_LOCAL_FINISHED +{ + /** + * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED + */ + struct GNUNET_MessageHeader header; +}; + +GNUNET_NETWORK_STRUCT_END +#endif +/* end of testing_cmds.h */ -- cgit v1.2.3