2 This file is part of GNUnet.
3 Copyright (C) 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 transport-testing-main.c
22 * @brief convenience main function for tests
23 * @author Christian Grothoff
25 #include "transport-testing.h"
29 * Closure for #connect_cb.
31 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
36 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
44 * Overall context we are in.
46 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
49 * Connect request this is about.
51 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
54 * Peer being connected.
56 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
59 * Peer being connected.
61 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
67 * Shutdown function for the test. Stops all peers.
69 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
72 do_shutdown (void *cls)
74 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
75 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
77 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
78 "Testcase shutting down\n");
79 if (NULL != ccc->shutdown_task)
80 ccc->shutdown_task (ccc->shutdown_task_cls);
81 if (NULL != ccc->timeout_task)
83 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
84 ccc->timeout_task = NULL;
86 if (NULL != ccc->connect_task)
88 GNUNET_SCHEDULER_cancel (ccc->connect_task);
89 ccc->connect_task = NULL;
91 while (NULL != (crl = ccc->crl_head))
93 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
96 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
99 for (unsigned int i=0;i<ccc->num_peers;i++)
101 if (NULL != ccc->p[i])
103 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
111 * Testcase hit timeout, shut it down with error.
113 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
116 do_timeout (void *cls)
118 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
120 ccc->timeout_task = NULL;
121 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
122 "Testcase timed out\n");
123 ccc->global_ret = GNUNET_SYSERR;
124 GNUNET_SCHEDULER_shutdown ();
129 * Internal data structure. Closure for
130 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
131 * Allows us to identify which peer this is about.
133 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
136 * Overall context of the callback.
138 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
141 * Offset of the peer this is about.
148 * Function called when we connected two peers.
149 * Once we have gotten to the clique, launch
150 * test-specific logic.
152 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
155 connect_cb (void *cls)
157 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
158 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
160 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
164 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
166 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
167 "Peers connected: %u (%s) <-> %u (%s)\n",
171 GNUNET_i2s (&crl->p2->id));
175 if (NULL == ccc->crl_head)
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "All connections UP, launching custom test logic.\n");
179 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
180 ccc->connect_continuation_cls);
186 * Find peer by peer ID.
188 * @param ccc context to search
189 * @param peer peer to look for
190 * @return NULL if @a peer was not found
192 struct GNUNET_TRANSPORT_TESTING_PeerContext *
193 GNUNET_TRANSPORT_TESTING_find_peer (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
194 const struct GNUNET_PeerIdentity *peer)
196 for (unsigned int i=0;i<ccc->num_peers;i++)
197 if ( (NULL != ccc->p[i]) &&
207 * Wrapper around peers connecting. Calls client's nc function.
209 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
210 * @param peer peer we got connected to
214 const struct GNUNET_PeerIdentity *peer)
216 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
217 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
228 * Wrapper around peers disconnecting. Calls client's nd function.
230 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
231 * @param peer peer we got disconnected from
235 const struct GNUNET_PeerIdentity *peer)
237 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
238 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
248 * Wrapper around receiving data. Calls client's rec function.
250 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
251 * @param peer peer we got a message from
252 * @param message message we received
256 const struct GNUNET_PeerIdentity *peer,
257 const struct GNUNET_MessageHeader *message)
259 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
260 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
262 if (NULL != ccc->rec)
271 * Connect the peers as a clique.
273 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
276 do_connect (void *cls)
278 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
280 ccc->connect_task = NULL;
281 for (unsigned int i=0;i<ccc->num_peers;i++)
282 for (unsigned int j=(ccc->bi_directional ? 0 : i+1);j<ccc->num_peers;j++)
284 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
288 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
289 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
296 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
298 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
299 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
303 GNUNET_i2s (&ccc->p[1]->id));
304 GNUNET_free (sender_c);
306 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
315 * Function called once we have successfully launched a peer.
316 * Once all peers have been launched, we connect all of them
319 * @param p peer that was launched (redundant, kill ASAP)
320 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
323 start_cb (struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
326 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
327 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
330 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
331 "Peer %u (`%s') started\n",
333 GNUNET_i2s (&p->id));
334 if (ccc->started != ccc->num_peers)
336 if (NULL != ccc->pre_connect_task)
338 /* Run the custom per-connect job, then give it a second to
339 go into effect before we continue connecting peers. */
340 ccc->pre_connect_task (ccc->pre_connect_task_cls);
341 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
353 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
354 * once the scheduler is up. Should launch the peers and
355 * then in the continuations try to connect them.
357 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
358 * @param args ignored
359 * @param cfgfile ignored
360 * @param cfg configuration
363 connect_check_run (void *cls,
366 const struct GNUNET_CONFIGURATION_Handle *cfg)
368 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
372 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
375 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
378 for (unsigned int i=0;i<ccc->num_peers;i++)
380 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
389 if (NULL == ccc->p[i])
394 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
395 "Fail! Could not start peers!\n");
396 GNUNET_SCHEDULER_shutdown ();
402 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
403 * Starts and connects the two peers, then invokes the
404 * `connect_continuation` from @a cls. Sets up a timeout to
405 * abort the test, and a shutdown handler to clean up properly
408 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
409 * @param tth_ initialized testing handle
410 * @param test_plugin_ name of the plugin
411 * @param test_name_ name of the test
412 * @param num_peers number of entries in the @a cfg_file array
413 * @param cfg_files array of names of configuration files for the peers
414 * @return #GNUNET_SYSERR on error
417 GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
418 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
419 const char *test_plugin_,
420 const char *test_name_,
421 unsigned int num_peers,
424 static struct GNUNET_GETOPT_CommandLineOption options[] = {
425 GNUNET_GETOPT_OPTION_END
427 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
428 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
429 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
433 (char *) ccc->config_file,
437 ccc->num_peers = num_peers;
438 ccc->cfg_files = cfg_files;
439 ccc->test_plugin = test_plugin_;
440 ccc->test_name = test_name_;
442 ccc->global_ret = GNUNET_OK;
445 for (unsigned int i=0;i<num_peers;i++)
450 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
457 return ccc->global_ret;
462 * Setup testcase. Calls @a check with the data the test needs.
464 * @param argv0 binary name (argv[0])
465 * @param filename source file name (__FILE__)
466 * @param num_peers number of peers to start
467 * @param check main function to run
468 * @param check_cls closure for @a check
469 * @return #GNUNET_OK on success
472 GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
473 const char *filename,
474 unsigned int num_peers,
475 GNUNET_TRANSPORT_TESTING_CheckCallback check,
478 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
482 char *cfg_names[num_peers];
486 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
487 GNUNET_log_setup (test_name,
490 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
491 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
493 for (unsigned int i=0;i<num_peers;i++)
494 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
496 tth = GNUNET_TRANSPORT_TESTING_init ();
503 ret = check (check_cls,
509 GNUNET_TRANSPORT_TESTING_done (tth);
511 for (unsigned int i=0;i<num_peers;i++)
512 GNUNET_free (cfg_names[i]);
513 GNUNET_free (test_source);
514 GNUNET_free (test_plugin);
515 GNUNET_free (test_name);
519 /* end of transport-testing-main.c */