2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file arm/test_exponential_backoff.c
22 * @brief testcase for gnunet-service-arm.c
23 * @author Christian Grothoff
26 #include "gnunet_arm_service.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
30 #define LOG(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
32 #define LOG_BACKOFF GNUNET_NO
34 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
36 #define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL
38 #define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5)
40 #define SERVICE "do-nothing"
42 #define BINARY "mockup-service"
44 #define CFGFILENAME "test_arm_api_data2.conf"
47 static const struct GNUNET_CONFIGURATION_Handle *cfg;
49 static struct GNUNET_ARM_Handle *arm;
51 static struct GNUNET_ARM_MonitorHandle *mon;
53 static struct GNUNET_SCHEDULER_Task *kt;
59 static int trialCount;
61 static struct GNUNET_TIME_Absolute startedWaitingAt;
63 struct GNUNET_TIME_Relative waitedFor;
65 struct GNUNET_TIME_Relative waitedFor_prev;
68 static FILE *killLogFilePtr;
70 static char *killLogFileName;
75 * Context for handling the shutdown of a service.
77 struct ShutdownContext
80 * Connection to the service that is being shutdown.
82 struct GNUNET_MQ_Handle *mq;
85 * Task set up to cancel the shutdown request on timeout.
87 struct GNUNET_SCHEDULER_Task *cancel_task;
93 kill_task (void *cbData);
97 * Shutting down took too long, cancel receive and return error.
102 service_shutdown_timeout (void *cls)
109 * Generic error handler, called with the appropriate error code and
110 * the same closure specified at the creation of the message queue.
111 * Not every message queue implementation supports an error handler.
113 * @param cls closure with the `struct ShutdownContext *`
114 * @param error error code
117 mq_error_handler (void *cls,
118 enum GNUNET_MQ_Error error)
120 struct ShutdownContext *shutdown_ctx = cls;
122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
123 "Service shutdown complete (MQ error).\n");
124 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
125 GNUNET_MQ_destroy (shutdown_ctx->mq);
126 GNUNET_free (shutdown_ctx);
131 kill_task (void *cbData)
133 struct ShutdownContext *shutdown_ctx
134 = GNUNET_new (struct ShutdownContext);
135 struct GNUNET_MQ_Envelope *env;
136 struct GNUNET_MessageHeader *msg;
137 struct GNUNET_MQ_MessageHandler handlers[] = {
138 GNUNET_MQ_handler_end ()
142 if (trialCount == 13)
144 LOG ("Saw enough kills, asking ARM to stop mock service for good\n");
145 GNUNET_ARM_request_service_stop (arm,
151 GNUNET_free (shutdown_ctx);
154 shutdown_ctx->mq = GNUNET_CLIENT_connect (cfg,
159 GNUNET_assert (NULL != shutdown_ctx->mq);
161 LOG ("Sending a shutdown request to the mock service\n");
162 env = GNUNET_MQ_msg (msg,
163 GNUNET_MESSAGE_TYPE_ARM_STOP); /* FIXME: abuse of message type */
164 GNUNET_MQ_send (shutdown_ctx->mq,
166 shutdown_ctx->cancel_task
167 = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
168 &service_shutdown_timeout,
174 trigger_disconnect (void *cls)
176 GNUNET_ARM_disconnect (arm);
177 GNUNET_ARM_monitor_stop (mon);
180 GNUNET_SCHEDULER_cancel (kt);
187 arm_stop_cb (void *cls,
188 enum GNUNET_ARM_RequestStatus status,
189 enum GNUNET_ARM_Result result)
191 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
192 GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED);
193 LOG ("ARM service stopped\n");
194 GNUNET_SCHEDULER_shutdown ();
199 srv_status (void *cls,
201 enum GNUNET_ARM_ServiceStatus status)
203 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
205 LOG ("ARM monitor started, starting mock service\n");
207 GNUNET_ARM_request_service_start (arm,
209 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
214 if (0 != strcasecmp (service, SERVICE))
215 return; /* not what we care about */
218 GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING);
219 GNUNET_break (phase == 1);
220 LOG ("do-nothing is starting\n");
223 GNUNET_assert (NULL == kt);
224 startedWaitingAt = GNUNET_TIME_absolute_get ();
225 kt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
231 /* We passively monitor ARM for status updates. ARM should tell us
232 * when do-nothing dies (no need to run a service upness test ourselves).
234 if (status == GNUNET_ARM_SERVICE_STARTING)
236 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
237 LOG ("Waited for: %s\n",
238 GNUNET_STRINGS_relative_time_to_string (waitedFor,
241 LOG ("do-nothing is starting, killing it...\n");
242 GNUNET_assert (NULL == kt);
243 kt = GNUNET_SCHEDULER_add_now (&kill_task, &ok);
245 else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14))
248 LOG ("do-nothing stopped working %u times, we are done here\n",
249 (unsigned int) trialCount);
250 GNUNET_ARM_request_service_stop (arm,
260 arm_start_cb (void *cls,
261 enum GNUNET_ARM_RequestStatus status,
262 enum GNUNET_ARM_Result result)
264 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
265 GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
266 GNUNET_break (phase == 0);
267 LOG ("Sent 'START' request for arm to ARM %s\n",
268 (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
276 const struct GNUNET_CONFIGURATION_Handle *c)
279 arm = GNUNET_ARM_connect (cfg, NULL, NULL);
285 mon = GNUNET_ARM_monitor_start (cfg,
291 GNUNET_ARM_disconnect (arm);
295 GNUNET_ARM_request_service_start (arm,
297 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
300 GNUNET_SCHEDULER_add_shutdown (&trigger_disconnect,
308 char *const argv[] = {
309 "test-exponential-backoff",
313 struct GNUNET_GETOPT_CommandLineOption options[] = {
314 GNUNET_GETOPT_OPTION_END
317 /* Running ARM and running the do_nothing task */
318 GNUNET_assert (GNUNET_OK ==
319 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
321 "test-exponential-backoff",
332 * Assumed maximum path length (for the log file name).
334 #define PATH_MAX 4096
341 struct GNUNET_CONFIGURATION_Handle *cfg;
345 cfg = GNUNET_CONFIGURATION_create ();
346 if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg,
347 "test_arm_api_data.conf"))
348 return GNUNET_SYSERR;
349 if (NULL == getcwd (pwd, PATH_MAX))
350 return GNUNET_SYSERR;
351 GNUNET_assert (0 < GNUNET_asprintf (&binary,
355 GNUNET_CONFIGURATION_set_value_string (cfg,
359 GNUNET_free (binary);
360 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg,
363 GNUNET_CONFIGURATION_destroy (cfg);
364 return GNUNET_SYSERR;
366 GNUNET_CONFIGURATION_destroy (cfg);
369 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log");
370 if (NULL == (killLogFilePtr = FOPEN (killLogFileName,
373 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
376 GNUNET_free (killLogFileName);
377 return GNUNET_SYSERR;
388 GNUNET_assert (0 == fclose (killLogFilePtr));
389 GNUNET_free (killLogFileName);
391 (void) unlink (CFGFILENAME);
396 main (int argc, char *argv[])
400 GNUNET_log_setup ("test-exponential-backoff",
404 if (GNUNET_OK != init ())
411 /* end of test_exponential_backoff.c */