From 925c210d978cd0e3dfc718d9e4c65ad713a817b9 Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Thu, 15 Apr 2021 15:35:28 +0200 Subject: - added handling of asynchronous task to testing ng. added testbed commands for setting up test invironment (atm wihtout the use of the ne async handling) --- src/include/gnunet_testbed_ng_service.h | 35 +-- src/include/gnunet_testing_ng_lib.h | 104 ++++----- src/testbed/testbed_api_cmd_controller.c | 1 - src/testbed/testbed_api_cmd_peer.c | 40 +++- src/testbed/testbed_api_cmd_peer_store.c | 60 ++++++ src/testbed/testbed_api_cmd_service.c | 140 ------------ src/testbed/testbed_api_cmd_tng_connect.c | 55 +++++ src/testbed/testbed_api_cmd_tng_service.c | 276 ++++++++++++++++++++++++ src/testing/testing.h | 74 +++++++ src/testing/testing_api_cmd_batch.c | 3 +- src/testing/testing_api_cmd_hello_world.c | 1 - src/testing/testing_api_cmd_hello_world_birth.c | 1 - src/testing/testing_api_loop.c | 186 +++++++++++++++- src/transport/transport-testing-ng.h | 71 ++++++ 14 files changed, 798 insertions(+), 249 deletions(-) create mode 100644 src/testbed/testbed_api_cmd_peer_store.c delete mode 100644 src/testbed/testbed_api_cmd_service.c create mode 100644 src/testbed/testbed_api_cmd_tng_connect.c create mode 100644 src/testbed/testbed_api_cmd_tng_service.c create mode 100644 src/testing/testing.h create mode 100644 src/transport/transport-testing-ng.h (limited to 'src') diff --git a/src/include/gnunet_testbed_ng_service.h b/src/include/gnunet_testbed_ng_service.h index a6f30889f..370617e68 100644 --- a/src/include/gnunet_testbed_ng_service.h +++ b/src/include/gnunet_testbed_ng_service.h @@ -38,33 +38,7 @@ #include "gnunet_util_lib.h" #include "gnunet_testing_ng_lib.h" -struct ServiceState -{ - /** - * Handle to operation - */ - struct GNUNET_TESTBED_Operation *operation; - - /** - * Flag indicating if service is ready. - */ - int service_ready; - - /** - * Abort task identifier - */ - struct GNUNET_SCHEDULER_Task *abort_task; - - /** - * Label of peer command. - */ - const char *peer_label; - - /** - * Name of service to start. - */ - const char *servicename; -}; +struct TngState; struct PeerCmdState { @@ -110,11 +84,6 @@ struct PeerCmdState */ struct GNUNET_SCHEDULER_Task *abort_task; - /** - * Handle for host registration - */ - struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle; - /** * Flag indicating if peer is ready. */ @@ -242,6 +211,6 @@ void GNUNET_TESTBED_shutdown_peer (struct PeerCmdState *ps); void -GNUNET_TESTBED_shutdown_service (struct ServiceState *ss); +GNUNET_TESTBED_shutdown_service (struct TngState *ss); #endif diff --git a/src/include/gnunet_testing_ng_lib.h b/src/include/gnunet_testing_ng_lib.h index 0bc516614..001d92aad 100644 --- a/src/include/gnunet_testing_ng_lib.h +++ b/src/include/gnunet_testing_ng_lib.h @@ -51,46 +51,7 @@ * Global state of the interpreter, used by a command * to access information about other commands. */ -// SUGGESTION: consider making this struct opaque (only known inside of libgnunettesting, -// say main loop and a few select commands, like next/fail/batch); + helper -// function to access 'cfg'? -struct GNUNET_TESTING_Interpreter -{ - - /** - * Commands the interpreter will run. - */ - struct GNUNET_TESTING_Command *commands; - - /** - * Interpreter task (if one is scheduled). - */ - struct GNUNET_SCHEDULER_Task *task; - - /** - * Our configuration. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Task run on timeout. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * Instruction pointer. Tells #interpreter_run() which instruction to run - * next. Need (signed) int because it gets -1 when rewinding the - * interpreter to the first CMD. - */ - int ip; - - /** - * Result of the testcases, #GNUNET_OK on success - */ - int result; - -}; - +struct GNUNET_TESTING_Interpreter; /** * A command to be run by the interpreter. @@ -131,20 +92,25 @@ struct GNUNET_TESTING_Command /** * Wait for any asynchronous execution of @e run to conclude, - * then call @a cont. Finish may only be called once per command. + * then call finish_cont. Finish may only be called once per command. * * This member may be NULL if this command is a synchronous command, * and also should be set to NULL once the command has finished. * + * @param cls closure * @param cont function to call upon completion, can be NULL * @param cont_cls closure for @a cont */ - // SUGGESTION (NEW!) - void + bool (*finish)(void *cls, - struct GNUNET_SCHEDULER_Task cont, + GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls); + /** + * Task for running the finish function. + */ + struct GNUNET_SCHEDULER_Task *finish_task; + /** * Clean up after the command. Run during forced termination * (CTRL-C) or test failure or test success. @@ -206,7 +172,6 @@ struct GNUNET_TESTING_Command * time, the interpreter will fail. Should be set generously to ensure * tests do not fail on slow systems. */ - // SUGGESTION (NEW): struct GNUNET_TIME_Relative default_timeout; /** @@ -215,12 +180,38 @@ struct GNUNET_TESTING_Command * #TALER_TESTING_cmd_finish() must be used * to ensure that a command actually completed. */ - // SUGGESTION (NEW): bool asynchronous_finish; }; +/** + * Struct to use for command-specific context information closure of a command waiting + * for another command. + */ +struct SyncState +{ + /** + * Closure for all commands with command-specific context information. + */ + void *cls; + + /** + * The asynchronous command the synchronous command of this closure waits for. + */ + const struct GNUNET_TESTING_Command *async_cmd; + + /** + * Task for running the finish method of the asynchronous task the command is waiting for. + */ + struct GNUNET_SCHEDULER_Task *finish_task; + + /** + * When did the execution of this commands finish function start? + */ + struct GNUNET_TIME_Absolute start_finish_time; +}; + /** * Lookup command by label. * @@ -243,15 +234,6 @@ GNUNET_TESTING_interpreter_get_current_label ( struct GNUNET_TESTING_Interpreter *is); -/** - * Current command is done, run the next one. - * - * @param is interpreter state. - */ -void -GNUNET_TESTING_interpreter_next (struct GNUNET_TESTING_Interpreter *is); - - /** * Current command failed, clean up and fail the test case. * @@ -271,14 +253,13 @@ GNUNET_TESTING_cmd_end (void); /** - * Turn synchronous command into asynchronous command. + * Turn asynchronous command into non blocking command by setting asynchronous_finish to true. * * @param cmd command to make synchronous. * @return a finish-command. */ -// SUGGESTION (NEW!) const struct GNUNET_TESTING_Command -TALER_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd); +GNUNET_TESTING_cmd_make_unblocking (const struct GNUNET_TESTING_Command cmd); /** @@ -292,11 +273,10 @@ TALER_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd); * @param timeout how long to wait at most for @a cmd_ref to finish * @return a finish-command. */ -// SUGGESTION (NEW!) const struct GNUNET_TESTING_Command -TALER_TESTING_cmd_finish (const char *finish_label, - const char *cmd_ref, - struct GNUNET_TIME_Relative timeout); +GNUNET_TESTING_cmd_finish (const char *finish_label, + const char *cmd_ref, + struct GNUNET_TIME_Relative timeout); /** diff --git a/src/testbed/testbed_api_cmd_controller.c b/src/testbed/testbed_api_cmd_controller.c index d65f41760..da23df1ef 100644 --- a/src/testbed/testbed_api_cmd_controller.c +++ b/src/testbed/testbed_api_cmd_controller.c @@ -121,7 +121,6 @@ registration_comp (void *cls, { cs->reg_handle = NULL; cs->host_ready = GNUNET_YES; - GNUNET_TESTING_interpreter_next (cs->is); } } diff --git a/src/testbed/testbed_api_cmd_peer.c b/src/testbed/testbed_api_cmd_peer.c index 4a727bc94..2e253e408 100644 --- a/src/testbed/testbed_api_cmd_peer.c +++ b/src/testbed/testbed_api_cmd_peer.c @@ -20,8 +20,8 @@ /** - * @file testbed/testbed_api_cmd_controller.c - * @brief Command to create a controller. + * @file testbed/testbed_api_cmd_peer.c + * @brief Command to create a peer. * @author t3sserakt */ #include "platform.h" @@ -54,10 +54,43 @@ peer_traits (void *cls, const char *trait, unsigned int index) { - (void) cls; + struct PeerCmdState *ps = cls; + + struct GNUNET_TESTING_Trait traits[] = { + { + .index = 0, + .trait_name = "peer", + .ptr = (const void *) ps->peer, + }, + GNUNET_TESTING_trait_end () + }; + + return GNUNET_TESTING_get_trait (traits, + ret, + trait, + index); + return GNUNET_OK; } +/** + * Offer data from trait + * + * @param cmd command to extract the controller from. + * @param peer pointer GNUNET_TESTBED_PEER + * @return #GNUNET_OK on success. + */ +int +GNUNET_TESTBED_get_trait_peer (const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTBED_Peer ** + peer) +{ + return cmd->traits (cmd->cls, + (const void **) peer, + "peer", + (unsigned int) 0); +} + /** * @@ -110,7 +143,6 @@ peer_started_cb (void *cls, if (NULL == emsg) { ps->peer_ready = GNUNET_YES; - GNUNET_TESTING_interpreter_next (ps->is); } else { diff --git a/src/testbed/testbed_api_cmd_peer_store.c b/src/testbed/testbed_api_cmd_peer_store.c new file mode 100644 index 000000000..fc96f589c --- /dev/null +++ b/src/testbed/testbed_api_cmd_peer_store.c @@ -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 + */ + +/** + * @file testbed/testbed_api_cmd_peer_store.c + * @brief Command to start the peer store service of a peer. + * @author t3sserakt + */ + + +static void +service_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct PeerStoreState *pss = cls; + + pss->psh = GNUNET_PEERSTORE_connect (pss->cfg); + GNUNET_TESTING_interpreter_next (ps->is); +} + + +struct GNUNET_TESTING_Command +GNUNET_TESTBED_cmd_peer_store (const char *label, + struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + struct PeerStoreState *pss; + + pss = GNUNET_new (struct PeerStoreState); + pss->cfg = cfg; + + struct GNUNET_TESTING_Command cmd = { + .cls = pss, + .label = label, + .run = &peer_store_run, + .cleanup = &peer_store_cleanup, + .traits = &peer_store_traits + }; + + return cmd; + +} diff --git a/src/testbed/testbed_api_cmd_service.c b/src/testbed/testbed_api_cmd_service.c deleted file mode 100644 index 58b3309de..000000000 --- a/src/testbed/testbed_api_cmd_service.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - 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 testbed/testbed_api_cmd_controller.c - * @brief Command to create a controller. - * @author t3sserakt - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_ng_lib.h" -#include "gnunet-service-testbed.h" -#include "testbed_api_hosts.h" -#include "gnunet_testbed_ng_service.h" - -/** - * Generic logging shortcut - */ -#define LOG(kind, ...) \ - GNUNET_log (kind, __VA_ARGS__) - - -/** - * abort task to run on test timed out - * - * @param cls NULL - * @param tc the task context - */ -static void -do_abort (void *cls) -{ - struct ServiceState *ss = cls; - - if (GNUNET_NO == ss->service_ready) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n"); - ss->abort_task = NULL; - GNUNET_TESTBED_shutdown_service (ss); - } -} - -/** -* -* -* @param cls closure -* @param cmd current CMD being cleaned up. -*/ -static void -service_cleanup (void *cls, - const struct GNUNET_TESTING_Command *cmd) -{ - (void) cls; -} - -/** -* -* -* @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 -service_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - return GNUNET_OK; -} - -static void -service_run (void *cls, - const struct GNUNET_TESTING_Command *cmd, - struct GNUNET_TESTING_Interpreter *is) -{ - struct ServiceState *ss = cls; - - // TODO this is unfinished code! - ss->operation = - GNUNET_TESTBED_service_connect (NULL, NULL, NULL, - NULL, NULL, - NULL, - NULL, NULL); - -} - -/** - * Shutdown nicely - * - * @param cs service state. - */ -void -GNUNET_TESTBED_shutdown_service (struct ServiceState *cs) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Shutting down...\n"); -} - - -struct GNUNET_TESTING_Command -GNUNET_TESTBED_cmd_service (const char *label, - const char *peer_label, - const char *servicename) -{ - struct ServiceState *ss; - - ss = GNUNET_new (struct ServiceState); - ss->servicename = servicename; - ss->peer_label = peer_label; - - struct GNUNET_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &service_run, - .cleanup = &service_cleanup, - .traits = &service_traits - }; - - return cmd; -} diff --git a/src/testbed/testbed_api_cmd_tng_connect.c b/src/testbed/testbed_api_cmd_tng_connect.c new file mode 100644 index 000000000..e52cd3c76 --- /dev/null +++ b/src/testbed/testbed_api_cmd_tng_connect.c @@ -0,0 +1,55 @@ +/* + 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 testbed/testbed_api_cmd_peer.c + * @brief Command to create a peer. + * @author t3sserakt + */ + + +static void +tng_connect_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct TngConnectState *tcs = cls; + + tcs->ah = GNUNET_TRANSPORT_application_init (tcs->cfg); +} + +struct GNUNET_TESTING_Command +GNUNET_TESTBED_cmd_tng_connect (const char *label) +{ + struct TngConnectState *tcs; + + ts = GNUNET_new (struct TngConnectState); + + struct GNUNET_TESTING_Command cmd = { + .cls = tcs, + .label = label, + .run = &tng_connect_run, + .cleanup = &tmg_connect_cleanup, + .traits = &tng_connect_traits + }; + + return cmd; +} diff --git a/src/testbed/testbed_api_cmd_tng_service.c b/src/testbed/testbed_api_cmd_tng_service.c new file mode 100644 index 000000000..f9ef44bad --- /dev/null +++ b/src/testbed/testbed_api_cmd_tng_service.c @@ -0,0 +1,276 @@ +/* + 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 testbed/testbed_api_cmd_tng.c + * @brief Command to start the transport service of a peer. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" +#include "gnunet-service-testbed.h" +#include "testbed_api_hosts.h" +#include "gnunet_testbed_ng_service.h" + +/** + * Generic logging shortcut + */ +#define LOG(kind, ...) \ + GNUNET_log (kind, __VA_ARGS__) + + +/** + * abort task to run on test timed out + * + * @param cls NULL + * @param tc the task context + */ +static void +do_abort (void *cls) +{ + struct TngState *ts = cls; + + if (GNUNET_NO == ts->service_ready) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n"); + ts->abort_task = NULL; + GNUNET_TESTBED_shutdown_service (ts); + } +} + +/** +* +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +tng_service_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + (void) cls; +} + +/** +* +* +* @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 +tng_service_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + return GNUNET_OK; +} + + +static void * +notify_connect (void *cls, + const struct GNUNET_PeerIdentity *peer, + struct GNUNET_MQ_Handle *mq) +{ + struct TngState *ts = cls; + + if (NULL != emsg) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "There was an error starting the transport subsystem: %s\n", + emsg); + } + GNUNET_TESTING_interpreter_next (ps->is); + return ts->nc (ts->cb_cls); + +} + + +static void +notify_disconnect (void *cls, + const struct GNUNET_PeerIdentity *peer, + void *handler_cls) +{ +} + + + + +/** + * Adapter function called to establish a connection to + * a service. + * + * @param cls closure + * @param cfg configuration of the peer to connect to; will be available until + * GNUNET_TESTBED_operation_done() is called on the operation returned + * from GNUNET_TESTBED_service_connect() + * @return service handle to return in 'op_result', NULL on error + */ +static void * +connect_adapter (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct TngState *ts = cls; + + service_handle = GNUNET_TRANSPORT_core_connect (cfg, + ts->peer_identity, + ts->handlers, + ts, + ¬ify_connect, + ¬ify_disconnect); + return service_handle; +} + + +/** + * Adapter function called to destroy a connection to + * a service. + * + * @param cls closure + * @param op_result service handle returned from the connect adapter + */ +static void +disconnect_adapter (void *cls, + void *op_result) +{ +} + +/** + * Callback to be called when a service connect operation is completed + * + * @param cls the callback closure from functions generating an operation + * @param op the operation that has been finished + * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter() + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +service_connect_comp_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + void *ca_result, + const char *emsg) +{ + struct TngState *ts = cls; + + if (NULL != emsg) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "An error occured connecting to service %s\n", + emsg); + GNUNET_TESTBED_operation_done (ts->operation); + } +} + + +/** + * Callback to be called when the requested peer information is available + * + * @param cls the closure from GNUNET_TESTBED_peer_getinformation() + * @param op the operation this callback corresponds to + * @param pinfo the result; will be NULL if the operation has failed + * @param emsg error message if the operation has failed; + * NULL if the operation is successfull + */ +static void +pi_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + const struct GNUNET_TESTBED_PeerInformation *pinfo, + const char *emsg) +{ + struct TngState *ts = cls; + + ts->peer_identity = pinfo->id; + ts->operation = + GNUNET_TESTBED_service_connect (NULL, peer, NULL, + &service_connect_comp_cb, ts, + &connect_adapter, + &disconnect_adapter, + ts); +} + + +static void +tng_service_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct TngState *ts = cls; + struct GNUNET_TESTBED_Peer *peer; + const struct GNUNET_TESTING_Command *peer_cmd; + + ts->is = is; + peer_cmd = GNUNET_TESTING_interpreter_lookup_command ( + ts->peer_label); + GNUNET_TESTBED_get_trait_peer (peer_cmd, + &peer); + + ts->operation = GNUNET_TESTBED_peer_get_information (peer, + GNUNET_TESTBED_PIT_IDENTITY, + &pi_cb, + ts); +} + +/** + * Shutdown nicely + * + * @param cs service state. + */ +void +GNUNET_TESTBED_shutdown_service (struct TngState *cs) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Shutting down...\n"); +} + + +struct GNUNET_TESTING_Command +GNUNET_TESTBED_cmd_tng_service (const char *label, + const char *peer_label, + const struct GNUNET_MQ_MessageHandler *handlers, + GNUNET_TRANSPORT_NotifyConnect nc, + void *cb_cls) + +{ + struct TngState *ts; + + ts = GNUNET_new (struct TngState); + ts->servicename = servicename; + ts->peer_label = peer_label; + ts->handlers = handlers; + ts->nc = nc; + ts->nd = nd; + ts->cb_cls; + + + struct GNUNET_TESTING_Command cmd = { + .cls = ts, + .label = label, + .run = &tng_service_run, + .cleanup = &tmg_service_cleanup, + .traits = &tng_service_traits + }; + + return cmd; +} diff --git a/src/testing/testing.h b/src/testing/testing.h new file mode 100644 index 000000000..b12466530 --- /dev/null +++ b/src/testing/testing.h @@ -0,0 +1,74 @@ +/* + 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 + */ + +#include "gnunet_util_lib.h" + +/** + * Global state of the interpreter, used by a command + * to access information about other commands. + */ +// SUGGESTION: consider making this struct opaque (only known inside of libgnunettesting, +// say main loop and a few select commands, like next/fail/batch); + helper +// function to access 'cfg'? +struct GNUNET_TESTING_Interpreter +{ + + /** + * Commands the interpreter will run. + */ + struct GNUNET_TESTING_Command *commands; + + /** + * Interpreter task (if one is scheduled). + */ + struct GNUNET_SCHEDULER_Task *task; + + /** + * Finish task of a blocking call to a commands finish method. + */ + struct GNUNET_SCHEDULER_Task *finish_task; + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Task run on timeout. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * Instruction pointer. Tells #interpreter_run() which instruction to run + * next. Need (signed) int because it gets -1 when rewinding the + * interpreter to the first CMD. + */ + int ip; + + /** + * Result of the testcases, #GNUNET_OK on success + */ + int result; + +}; diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c index 531778129..af260f80d 100644 --- a/src/testing/testing_api_cmd_batch.c +++ b/src/testing/testing_api_cmd_batch.c @@ -26,7 +26,7 @@ */ #include "platform.h" #include "gnunet_testing_ng_lib.h" - +#include "testing.h" /** * State for a "batch" CMD. @@ -70,7 +70,6 @@ batch_run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Exiting from batch: %s\n", cmd->label); - GNUNET_TESTING_interpreter_next (is); return; } bs->batch[bs->batch_ip].start_time diff --git a/src/testing/testing_api_cmd_hello_world.c b/src/testing/testing_api_cmd_hello_world.c index 8c1d7353d..4347ac818 100644 --- a/src/testing/testing_api_cmd_hello_world.c +++ b/src/testing/testing_api_cmd_hello_world.c @@ -89,7 +89,6 @@ hello_world_run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Now I am a %s\n", hs->message); - GNUNET_TESTING_interpreter_next (is); } /** diff --git a/src/testing/testing_api_cmd_hello_world_birth.c b/src/testing/testing_api_cmd_hello_world_birth.c index 0faf93cd8..2a5bded92 100644 --- a/src/testing/testing_api_cmd_hello_world_birth.c +++ b/src/testing/testing_api_cmd_hello_world_birth.c @@ -112,7 +112,6 @@ hello_world_birth_run (void *cls, { hbs->what_am_i = "boy!"; } - GNUNET_TESTING_interpreter_next (is); } /** diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index f29329a60..dbd86ba90 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -28,9 +28,49 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_testing_ng_lib.h" +#include "testing.h" struct GNUNET_TESTING_Interpreter *is; +/** + * Closure used to sync an asynchronous with an synchronous command. + */ +struct SyncTaskClosure +{ + + /** + * The asynchronous command the synchronous command waits for. + */ + const struct GNUNET_TESTING_Command *async_cmd; + + /** + * The synchronous command that waits for the asynchronous command. + */ + const struct GNUNET_TESTING_Command *sync_cmd; + + /** + * The interpreter of the test. + */ + struct GNUNET_TESTING_Interpreter *is; +}; + +/** +* Closure used to run the finish task. +*/ +struct FinishTaskClosure +{ + + /** + * The asynchronous command the synchronous command waits for. + */ + const struct GNUNET_TESTING_Command *cmd; + + /** + * The interpreter of the test. + */ + struct GNUNET_TESTING_Interpreter *is; +}; + /** * Lookup command by label. * @@ -107,9 +147,10 @@ interpreter_run (void *cls); /** * Current command is done, run the next one. */ -void -GNUNET_TESTING_interpreter_next (struct GNUNET_TESTING_Interpreter *is) +static void +interpreter_next (void *cls) { + struct GNUNET_TESTING_Interpreter *is = cls; static unsigned long long ipc; static struct GNUNET_TIME_Absolute last_report; struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; @@ -141,6 +182,123 @@ GNUNET_TESTING_interpreter_next (struct GNUNET_TESTING_Interpreter *is) } +static void +run_finish_task_next (void *cls) +{ + struct FinishTaskClosure *ftc = cls; + const struct GNUNET_TESTING_Command *cmd = ftc->cmd; + struct GNUNET_TESTING_Interpreter *is = ftc->is; + + if (cmd->finish (cmd->cls, &interpreter_next, is)) + { + is->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_next, ftc); + } + else + { + is->finish_task = NULL; + } + +} + + +static void +run_finish_task_sync (void *cls) +{ + struct SyncTaskClosure *stc = cls; + const struct GNUNET_TESTING_Command *cmd = stc->async_cmd; + const struct GNUNET_TESTING_Command *sync_cmd = stc->sync_cmd; + struct FinishTaskClosure *ftc; + struct SyncState *sync_state = sync_cmd->cls; + struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task; + + GNUNET_assert (NULL != finish_task); + ftc = GNUNET_new (struct FinishTaskClosure); + ftc->cmd = stc->sync_cmd; + ftc->is = stc->is; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + if (cmd->default_timeout.rel_value_us < now.abs_value_us + - sync_state->start_finish_time.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "The command with label %s did not finish its asyncronous task in time.\n", + cmd->label); + is->result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + } + + if (cmd->finish (cmd->cls, run_finish_task_next, ftc)) + { + finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, stc); + } + else + { + finish_task = NULL; + } +} + + +static void +start_finish_on_ref (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct SyncState *sync_state = cls; + struct SyncTaskClosure *stc; + const struct GNUNET_TESTING_Command *async_cmd; + + async_cmd = sync_state->async_cmd; + stc = GNUNET_new (struct SyncTaskClosure); + stc->async_cmd = async_cmd; + stc->sync_cmd = cmd; + stc->is = is; + sync_state->start_finish_time = GNUNET_TIME_absolute_get (); + sync_state->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, + stc); +} + + +const struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_finish (const char *finish_label, + const char *cmd_ref, + struct GNUNET_TIME_Relative timeout) +{ + const struct GNUNET_TESTING_Command *async_cmd; + struct SyncState *sync_state; + + async_cmd = GNUNET_TESTING_interpreter_lookup_command (cmd_ref); + sync_state = GNUNET_new (struct SyncState); + sync_state->async_cmd = async_cmd; + + struct GNUNET_TESTING_Command cmd = { + .cls = sync_state, + .label = finish_label, + .run = &start_finish_on_ref, + .asynchronous_finish = GNUNET_NO + }; + + return cmd; +} + + +const struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd) +{ + + GNUNET_assert (NULL != cmd.finish); + const struct GNUNET_TESTING_Command async_cmd = { + .cls = cmd.cls, + .label = cmd.label, + .run = cmd.run, + .cleanup = cmd.cleanup, + .traits = cmd.traits, + .finish = cmd.finish, + .asynchronous_finish = GNUNET_YES + }; + + return async_cmd; +} + + /** * Current command failed, clean up and fail the test case. * @@ -195,14 +353,15 @@ GNUNET_TESTING_interpreter_get_current_label (struct /** - * Run the main interpreter loop that performs exchange operations. + * Run the main interpreter loop. * * @param cls contains the `struct GNUNET_TESTING_Interpreter` */ static void interpreter_run (void *cls) { - (void) cls; + struct FinishTaskClosure *ftc; + struct GNUNET_TESTING_Interpreter *is = cls; struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; is->task = NULL; @@ -227,6 +386,17 @@ interpreter_run (void *cls) cmd->run (cmd->cls, cmd, is); + if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish)) + { + ftc = GNUNET_new (struct FinishTaskClosure); + ftc->cmd = cmd; + ftc->is = is; + cmd->finish_task = GNUNET_SCHEDULER_add_now (run_finish_task_next, ftc); + } + else + { + interpreter_next (is); + } } @@ -253,9 +423,15 @@ do_shutdown (void *cls) for (unsigned int j = 0; NULL != (cmd = &is->commands[j])->label; - j++) + j++) { cmd->cleanup (cmd->cls, cmd); + if (NULL != cmd->finish_task) + { + GNUNET_SCHEDULER_cancel (cmd->finish_task); + cmd->finish_task = NULL; + } + } if (NULL != is->task) { diff --git a/src/transport/transport-testing-ng.h b/src/transport/transport-testing-ng.h new file mode 100644 index 000000000..cd5ba65a9 --- /dev/null +++ b/src/transport/transport-testing-ng.h @@ -0,0 +1,71 @@ +/* + 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 + */ + +struct TngState +{ + /** + * Handle to operation + */ + struct GNUNET_TESTBED_Operation *operation; + + /** + * Flag indicating if service is ready. + */ + int service_ready; + + /** + * Abort task identifier + */ + struct GNUNET_SCHEDULER_Task *abort_task; + + /** + * Label of peer command. + */ + const char *peer_label; + + /** + * Name of service to start. + */ + const char *servicename; + + /** + * Peer identity of the system. + */ + struct GNUNET_PeerIdentity *peer_identity; + + /** + * Message handler for transport service. + */ + const struct GNUNET_MQ_MessageHandler *handlers; + + /** + * Notify connect callback + */ + GNUNET_TRANSPORT_NotifyConnect nc; + + /** + * Closure for the @a nc callback + */ + void *cb_cls; +}; -- cgit v1.2.3