aboutsummaryrefslogtreecommitdiff
path: root/src/service/arm/test_exponential_backoff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/arm/test_exponential_backoff.c')
-rw-r--r--src/service/arm/test_exponential_backoff.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/src/service/arm/test_exponential_backoff.c b/src/service/arm/test_exponential_backoff.c
new file mode 100644
index 000000000..e3eed8568
--- /dev/null
+++ b/src/service/arm/test_exponential_backoff.c
@@ -0,0 +1,416 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file arm/test_exponential_backoff.c
22 * @brief testcase for gnunet-service-arm.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_arm_service.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29
30#define LOG(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
31
32#define LOG_BACKOFF GNUNET_NO
33
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
35
36#define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL
37
38#define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply ( \
39 GNUNET_TIME_UNIT_MILLISECONDS, 5)
40
41#define SERVICE "do-nothing"
42
43#define BINARY "mockup-service"
44
45#define CFGFILENAME "test_arm_api_data2.conf"
46
47
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50static struct GNUNET_ARM_Handle *arm;
51
52static struct GNUNET_ARM_MonitorHandle *mon;
53
54static struct GNUNET_SCHEDULER_Task *kt;
55
56static int ok = 1;
57
58static int phase = 0;
59
60static int trialCount;
61
62static struct GNUNET_TIME_Absolute startedWaitingAt;
63
64struct GNUNET_TIME_Relative waitedFor;
65
66struct GNUNET_TIME_Relative waitedFor_prev;
67
68#if LOG_BACKOFF
69static FILE *killLogFilePtr;
70
71static char *killLogFileName;
72#endif
73
74
75/**
76 * Context for handling the shutdown of a service.
77 */
78struct ShutdownContext
79{
80 /**
81 * Connection to the service that is being shutdown.
82 */
83 struct GNUNET_MQ_Handle *mq;
84
85 /**
86 * Task set up to cancel the shutdown request on timeout.
87 */
88 struct GNUNET_SCHEDULER_Task *cancel_task;
89};
90
91
92static void
93kill_task (void *cbData);
94
95
96/**
97 * Shutting down took too long, cancel receive and return error.
98 *
99 * @param cls closure
100 */
101static void
102service_shutdown_timeout (void *cls)
103{
104 GNUNET_assert (0);
105}
106
107
108/**
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.
112 *
113 * @param cls closure with the `struct ShutdownContext *`
114 * @param error error code
115 */
116static void
117mq_error_handler (void *cls,
118 enum GNUNET_MQ_Error error)
119{
120 struct ShutdownContext *shutdown_ctx = cls;
121
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);
127}
128
129
130static void
131kill_task (void *cbData)
132{
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 ()
139 };
140
141 kt = NULL;
142 if (trialCount == 13)
143 {
144 LOG ("Saw enough kills, asking ARM to stop mock service for good\n");
145 GNUNET_ARM_request_service_stop (arm,
146 SERVICE,
147 NULL,
148 NULL);
149 ok = 0;
150 trialCount++;
151 GNUNET_free (shutdown_ctx);
152 return;
153 }
154 shutdown_ctx->mq = GNUNET_CLIENT_connect (cfg,
155 SERVICE,
156 handlers,
157 &mq_error_handler,
158 shutdown_ctx);
159 GNUNET_assert (NULL != shutdown_ctx->mq);
160 trialCount++;
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,
165 env);
166 shutdown_ctx->cancel_task
167 = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
168 &service_shutdown_timeout,
169 shutdown_ctx);
170}
171
172
173static void
174trigger_disconnect (void *cls)
175{
176 GNUNET_ARM_disconnect (arm);
177 GNUNET_ARM_monitor_stop (mon);
178 if (NULL != kt)
179 {
180 GNUNET_SCHEDULER_cancel (kt);
181 kt = NULL;
182 }
183}
184
185
186static void
187arm_stop_cb (void *cls,
188 enum GNUNET_ARM_RequestStatus status,
189 enum GNUNET_ARM_Result result)
190{
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 ();
195}
196
197
198static void
199srv_status (void *cls,
200 const char *service,
201 enum GNUNET_ARM_ServiceMonitorStatus status)
202{
203 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
204 {
205 LOG ("ARM monitor started, starting mock service\n");
206 phase++;
207 GNUNET_ARM_request_service_start (arm,
208 SERVICE,
209 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
210 NULL,
211 NULL);
212 return;
213 }
214 if (0 != strcasecmp (service, SERVICE))
215 return; /* not what we care about */
216 if (phase == 1)
217 {
218 GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING);
219 GNUNET_break (phase == 1);
220 LOG ("do-nothing is starting\n");
221 phase++;
222 ok = 1;
223 GNUNET_assert (NULL == kt);
224 startedWaitingAt = GNUNET_TIME_absolute_get ();
225 kt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
226 &kill_task,
227 NULL);
228 }
229 else if (phase == 2)
230 {
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).
233 */
234 if (status == GNUNET_ARM_SERVICE_STARTING)
235 {
236 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
237 LOG ("Waited for: %s\n",
238 GNUNET_STRINGS_relative_time_to_string (waitedFor,
239 GNUNET_YES));
240
241 LOG ("do-nothing is starting, killing it...\n");
242 GNUNET_assert (NULL == kt);
243 kt = GNUNET_SCHEDULER_add_now (&kill_task, &ok);
244 }
245 else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14))
246 {
247 phase++;
248 LOG ("do-nothing stopped working %u times, we are done here\n",
249 (unsigned int) trialCount);
250 GNUNET_ARM_request_service_stop (arm,
251 "arm",
252 &arm_stop_cb,
253 NULL);
254 }
255 }
256}
257
258
259static void
260arm_start_cb (void *cls,
261 enum GNUNET_ARM_RequestStatus status,
262 enum GNUNET_ARM_Result result)
263{
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" :
269 "unsuccessfully");
270}
271
272
273static void
274task (void *cls,
275 char *const *args,
276 const char *cfgfile,
277 const struct GNUNET_CONFIGURATION_Handle *c)
278{
279 cfg = c;
280 arm = GNUNET_ARM_connect (cfg, NULL, NULL);
281 if (NULL == arm)
282 {
283 GNUNET_break (0);
284 return;
285 }
286 mon = GNUNET_ARM_monitor_start (cfg,
287 &srv_status,
288 NULL);
289 if (NULL == mon)
290 {
291 GNUNET_break (0);
292 GNUNET_ARM_disconnect (arm);
293 arm = NULL;
294 return;
295 }
296 GNUNET_ARM_request_service_start (arm,
297 "arm",
298 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
299 &arm_start_cb,
300 NULL);
301 GNUNET_SCHEDULER_add_shutdown (&trigger_disconnect,
302 NULL);
303}
304
305
306static int
307check ()
308{
309 char *const argv[] = {
310 "test-exponential-backoff",
311 "-c", CFGFILENAME,
312 NULL
313 };
314 struct GNUNET_GETOPT_CommandLineOption options[] = {
315 GNUNET_GETOPT_OPTION_END
316 };
317
318 /* Running ARM and running the do_nothing task */
319 GNUNET_assert (GNUNET_OK ==
320 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
321 argv,
322 "test-exponential-backoff",
323 "nohelp",
324 options,
325 &task,
326 NULL));
327 return ok;
328}
329
330
331#ifndef PATH_MAX
332/**
333 * Assumed maximum path length (for the log file name).
334 */
335#define PATH_MAX 4096
336#endif
337
338
339static int
340init ()
341{
342 struct GNUNET_CONFIGURATION_Handle *cfg;
343 char pwd[PATH_MAX];
344 char *binary;
345
346 cfg = GNUNET_CONFIGURATION_create ();
347 if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg,
348 "test_arm_api_data.conf"))
349 {
350 GNUNET_CONFIGURATION_destroy (cfg);
351 return GNUNET_SYSERR;
352 }
353 if (NULL == getcwd (pwd, PATH_MAX))
354 return GNUNET_SYSERR;
355 GNUNET_assert (0 < GNUNET_asprintf (&binary,
356 "%s/%s",
357 pwd,
358 BINARY));
359 GNUNET_CONFIGURATION_set_value_string (cfg,
360 SERVICE,
361 "BINARY",
362 binary);
363 GNUNET_free (binary);
364 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg,
365 CFGFILENAME))
366 {
367 GNUNET_CONFIGURATION_destroy (cfg);
368 return GNUNET_SYSERR;
369 }
370 GNUNET_CONFIGURATION_destroy (cfg);
371
372#if LOG_BACKOFF
373 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log");
374 if (NULL == (killLogFilePtr = fopen (killLogFileName,
375 "w")))
376 {
377 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
378 "fopen",
379 killLogFileName);
380 GNUNET_free (killLogFileName);
381 return GNUNET_SYSERR;
382 }
383#endif
384 return GNUNET_OK;
385}
386
387
388static void
389houseKeep ()
390{
391#if LOG_BACKOFF
392 GNUNET_assert (0 == fclose (killLogFilePtr));
393 GNUNET_free (killLogFileName);
394#endif
395 (void) unlink (CFGFILENAME);
396}
397
398
399int
400main (int argc, char *argv[])
401{
402 int ret;
403
404 GNUNET_log_setup ("test-exponential-backoff",
405 "WARNING",
406 NULL);
407
408 if (GNUNET_OK != init ())
409 return 1;
410 ret = check ();
411 houseKeep ();
412 return ret;
413}
414
415
416/* end of test_exponential_backoff.c */