X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Farm%2Ftest_exponential_backoff.c;h=0905f145d593f44b018fe4c922ea7f549cb5386f;hb=c1a9bb5df380beb363f56116bad6bd2e37df536a;hp=425e6bd8d0f9e8c067f62f89ca7728791a62e8d5;hpb=0642778223aed4c0a2ef03eed1362afb041194f3;p=oweals%2Fgnunet.git diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c index 425e6bd8d..0905f145d 100644 --- a/src/arm/test_exponential_backoff.c +++ b/src/arm/test_exponential_backoff.c @@ -1,10 +1,10 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + Copyright (C) 2009, 2016 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -14,232 +14,381 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** * @file arm/test_exponential_backoff.c * @brief testcase for gnunet-service-arm.c + * @author Christian Grothoff */ #include "platform.h" #include "gnunet_arm_service.h" -#include "gnunet_client_lib.h" -#include "gnunet_configuration_lib.h" -#include "gnunet_program_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" + +#define LOG(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) -#define VERBOSE GNUNET_NO -#define START_ARM GNUNET_YES #define LOG_BACKOFF GNUNET_NO + #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + #define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL + #define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5) -static struct GNUNET_SCHEDULER_Handle *sched; +#define SERVICE "do-nothing" + +#define BINARY "mockup-service" + +#define CFGFILENAME "test_arm_api_data2.conf" + + static const struct GNUNET_CONFIGURATION_Handle *cfg; + static struct GNUNET_ARM_Handle *arm; + +static struct GNUNET_ARM_MonitorHandle *mon; + +static struct GNUNET_SCHEDULER_Task *kt; + static int ok = 1; +static int phase = 0; + +static int trialCount; + +static struct GNUNET_TIME_Absolute startedWaitingAt; + +struct GNUNET_TIME_Relative waitedFor; + +struct GNUNET_TIME_Relative waitedFor_prev; + #if LOG_BACKOFF static FILE *killLogFilePtr; + static char *killLogFileName; #endif -static void -arm_notify_stop (void *cls, int success) +/** + * Context for handling the shutdown of a service. + */ +struct ShutdownContext { - GNUNET_assert (success == GNUNET_NO); -#if START_ARM - GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL); -#endif -} + /** + * Connection to the service that is being shutdown. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Task set up to cancel the shutdown request on timeout. + */ + struct GNUNET_SCHEDULER_Task *cancel_task; + +}; static void -kill_task (void *cbData, - const struct GNUNET_SCHEDULER_TaskContext *tc); +kill_task (void *cbData); +/** + * Shutting down took too long, cancel receive and return error. + * + * @param cls closure + */ static void -do_nothing_notify (void *cls, int success) +service_shutdown_timeout (void *cls) { - GNUNET_assert (success == GNUNET_YES); - ok = 1; - GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_UNIT_SECONDS, - &kill_task, NULL); + GNUNET_assert (0); } +/** + * Generic error handler, called with the appropriate error code and + * the same closure specified at the creation of the message queue. + * Not every message queue implementation supports an error handler. + * + * @param cls closure with the `struct ShutdownContext *` + * @param error error code + */ static void -arm_notify (void *cls, int success) -{ - GNUNET_assert (success == GNUNET_YES); - GNUNET_ARM_start_service (arm, - "do-nothing", TIMEOUT, - &do_nothing_notify, NULL); +mq_error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct ShutdownContext *shutdown_ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Service shutdown complete (MQ error).\n"); + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_MQ_destroy (shutdown_ctx->mq); + GNUNET_free (shutdown_ctx); } static void -kill_task (void *cbData, - const struct GNUNET_SCHEDULER_TaskContext *tc); - +kill_task (void *cbData) +{ + struct ShutdownContext *shutdown_ctx + = GNUNET_new (struct ShutdownContext); + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_handler_end () + }; -static void -do_nothing_restarted_notify_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - static char a; - static int trialCount = 0; - + kt = NULL; + if (trialCount == 13) + { + LOG ("Saw enough kills, asking ARM to stop mock service for good\n"); + GNUNET_ARM_request_service_stop (arm, + SERVICE, + NULL, + NULL); + ok = 0; + trialCount++; + GNUNET_free (shutdown_ctx); + return; + } + shutdown_ctx->mq = GNUNET_CLIENT_connect (cfg, + SERVICE, + handlers, + &mq_error_handler, + shutdown_ctx); + GNUNET_assert (NULL != shutdown_ctx->mq); trialCount++; + LOG ("Sending a shutdown request to the mock service\n"); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_ARM_STOP); /* FIXME: abuse of message type */ + GNUNET_MQ_send (shutdown_ctx->mq, + env); + shutdown_ctx->cancel_task + = GNUNET_SCHEDULER_add_delayed (TIMEOUT, + &service_shutdown_timeout, + shutdown_ctx); +} -#if LOG_BACKOFF - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - fprintf(killLogFilePtr, - "%d.Reason is shutdown!\n", - trialCount); - } - else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) - { - fprintf(killLogFilePtr, - "%d.Reason is timeout!\n", - trialCount); - } - else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0) - { - fprintf(killLogFilePtr, - "%d.Service is running!\n", - trialCount); - } -#endif - GNUNET_SCHEDULER_add_now (sched, &kill_task, &a); + +static void +trigger_disconnect (void *cls) +{ + GNUNET_ARM_disconnect (arm); + GNUNET_ARM_monitor_stop (mon); + if (NULL != kt) + { + GNUNET_SCHEDULER_cancel (kt); + kt = NULL; + } } static void -do_test (void *cbData, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_CLIENT_service_test(sched, "do-nothing", - cfg, TIMEOUT, - &do_nothing_restarted_notify_task, NULL); +arm_stop_cb (void *cls, + enum GNUNET_ARM_RequestStatus status, + enum GNUNET_ARM_Result result) +{ + GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); + GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED); + LOG ("ARM service stopped\n"); + GNUNET_SCHEDULER_shutdown (); } static void -kill_task (void *cbData, - const struct GNUNET_SCHEDULER_TaskContext *tc) +srv_status (void *cls, + const char *service, + enum GNUNET_ARM_ServiceStatus status) { - static struct GNUNET_CLIENT_Connection * doNothingConnection = NULL; - static struct GNUNET_TIME_Absolute startedWaitingAt; - struct GNUNET_TIME_Relative waitedFor; - static int trialCount = 0; - - if (NULL != cbData) { - waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); -#if LOG_BACKOFF - fprintf(killLogFilePtr, - "Waited for: %llu ms\n", - (unsigned long long) waitedFor.value); -#endif - } - else - waitedFor.value = 0; - /* Connect to the doNothing task */ - doNothingConnection = GNUNET_CLIENT_connect (sched, "do-nothing", cfg); -#if LOG_BACKOFF - if (NULL == doNothingConnection) - fprintf(killLogFilePtr, - "Unable to connect to do-nothing process!\n"); -#endif - if (trialCount == 12) { - GNUNET_ARM_stop_service (arm, - "do-nothing", - TIMEOUT, - &arm_notify_stop, NULL); - ok = 0; + if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED) + { + LOG ("ARM monitor started, starting mock service\n"); + phase++; + GNUNET_ARM_request_service_start (arm, + SERVICE, + GNUNET_OS_INHERIT_STD_OUT_AND_ERR, + NULL, + NULL); return; } - - /* Use the created connection to kill the doNothingTask */ - GNUNET_CLIENT_service_shutdown(doNothingConnection); - trialCount++; - startedWaitingAt = GNUNET_TIME_absolute_get(); - GNUNET_SCHEDULER_add_delayed (sched, - waitedFor, - &do_test, - NULL); + if (0 != strcasecmp (service, SERVICE)) + return; /* not what we care about */ + if (phase == 1) + { + GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING); + GNUNET_break (phase == 1); + LOG ("do-nothing is starting\n"); + phase++; + ok = 1; + GNUNET_assert (NULL == kt); + startedWaitingAt = GNUNET_TIME_absolute_get (); + kt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &kill_task, + NULL); + } + else if (phase == 2) + { + /* We passively monitor ARM for status updates. ARM should tell us + * when do-nothing dies (no need to run a service upness test ourselves). + */ + if (status == GNUNET_ARM_SERVICE_STARTING) + { + waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); + LOG ("Waited for: %s\n", + GNUNET_STRINGS_relative_time_to_string (waitedFor, + GNUNET_YES)); + + LOG ("do-nothing is starting, killing it...\n"); + GNUNET_assert (NULL == kt); + kt = GNUNET_SCHEDULER_add_now (&kill_task, &ok); + } + else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14)) + { + phase++; + LOG ("do-nothing stopped working %u times, we are done here\n", + (unsigned int) trialCount); + GNUNET_ARM_request_service_stop (arm, + "arm", + &arm_stop_cb, + NULL); + } + } } - + +static void +arm_start_cb (void *cls, + enum GNUNET_ARM_RequestStatus status, + enum GNUNET_ARM_Result result) +{ + GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); + GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); + GNUNET_break (phase == 0); + LOG ("Sent 'START' request for arm to ARM %s\n", + (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); +} + + static void task (void *cls, - struct GNUNET_SCHEDULER_Handle *s, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; - sched = s; - - arm = GNUNET_ARM_connect (cfg, sched, NULL); -#if START_ARM - GNUNET_ARM_start_service (arm, "arm", GNUNET_TIME_UNIT_ZERO, &arm_notify, NULL); -#else - arm_do_nothing (NULL, GNUNET_YES); -#endif + arm = GNUNET_ARM_connect (cfg, NULL, NULL); + if (NULL == arm) + { + GNUNET_break (0); + return; + } + mon = GNUNET_ARM_monitor_start (cfg, + &srv_status, + NULL); + if (NULL == mon) + { + GNUNET_break (0); + GNUNET_ARM_disconnect (arm); + arm = NULL; + return; + } + GNUNET_ARM_request_service_start (arm, + "arm", + GNUNET_OS_INHERIT_STD_OUT_AND_ERR, + &arm_start_cb, + NULL); + GNUNET_SCHEDULER_add_shutdown (&trigger_disconnect, + NULL); } + static int check () { char *const argv[] = { - "test-arm-api", - "-c", "test_arm_api_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif + "test-exponential-backoff", + "-c", CFGFILENAME, NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; - + /* Running ARM and running the do_nothing task */ GNUNET_assert (GNUNET_OK == - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, - argv, + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-exponential-backoff", - "nohelp", options, &task, NULL)); - - + "nohelp", + options, + &task, + NULL)); return ok; } + +#ifndef PATH_MAX +/** + * Assumed maximum path length (for the log file name). + */ +#define PATH_MAX 4096 +#endif + + static int -init() +init () { -#if LOG_BACKOFF - killLogFileName = GNUNET_DISK_mktemp("exponential-backoff-waiting.log"); - if (NULL == (killLogFilePtr = FOPEN(killLogFileName, "w"))) { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", killLogFileName); - GNUNET_free (killLogFileName); + struct GNUNET_CONFIGURATION_Handle *cfg; + char pwd[PATH_MAX]; + char *binary; + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, + "test_arm_api_data.conf")) + return GNUNET_SYSERR; + if (NULL == getcwd (pwd, PATH_MAX)) return GNUNET_SYSERR; - } + GNUNET_assert (0 < GNUNET_asprintf (&binary, + "%s/%s", + pwd, + BINARY)); + GNUNET_CONFIGURATION_set_value_string (cfg, + SERVICE, + "BINARY", + binary); + GNUNET_free (binary); + if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, + CFGFILENAME)) + { + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + GNUNET_CONFIGURATION_destroy (cfg); + +#if LOG_BACKOFF + killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log"); + if (NULL == (killLogFilePtr = FOPEN (killLogFileName, + "w"))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "fopen", + killLogFileName); + GNUNET_free (killLogFileName); + return GNUNET_SYSERR; + } #endif return GNUNET_OK; } static void -houseKeep() +houseKeep () { #if LOG_BACKOFF GNUNET_assert (0 == fclose (killLogFilePtr)); - GNUNET_free(killLogFileName); + GNUNET_free (killLogFileName); #endif + (void) unlink (CFGFILENAME); } @@ -249,16 +398,13 @@ main (int argc, char *argv[]) int ret; GNUNET_log_setup ("test-exponential-backoff", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - - init(); + "WARNING", + NULL); + + if (GNUNET_OK != init ()) + return 1; ret = check (); - houseKeep(); + houseKeep (); return ret; }