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 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.
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.
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/>.
19 * @file transport-testing-main.c
20 * @brief convenience main function for tests
21 * @author Christian Grothoff
23 #include "transport-testing.h"
27 * Closure for #connect_cb.
29 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
34 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
39 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
42 * Overall context we are in.
44 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47 * Connect request this is about.
49 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
52 * Peer being connected.
54 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
57 * Peer being connected.
59 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
65 * Shutdown function for the test. Stops all peers.
67 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
70 do_shutdown (void *cls)
72 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
73 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
75 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
76 "Testcase shutting down\n");
77 if (NULL != ccc->shutdown_task)
78 ccc->shutdown_task (ccc->shutdown_task_cls);
79 if (NULL != ccc->timeout_task)
81 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
82 ccc->timeout_task = NULL;
84 if (NULL != ccc->connect_task)
86 GNUNET_SCHEDULER_cancel (ccc->connect_task);
87 ccc->connect_task = NULL;
89 while (NULL != (crl = ccc->crl_head))
91 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
94 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
97 for (unsigned int i=0;i<ccc->num_peers;i++)
99 if (NULL != ccc->p[i])
101 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
109 * Testcase hit timeout, shut it down with error.
111 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
114 do_timeout (void *cls)
116 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
118 ccc->timeout_task = NULL;
119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
120 "Testcase timed out\n");
121 ccc->global_ret = GNUNET_SYSERR;
122 GNUNET_SCHEDULER_shutdown ();
127 * Internal data structure. Closure for
128 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
129 * Allows us to identify which peer this is about.
131 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
134 * Overall context of the callback.
136 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
139 * Offset of the peer this is about.
146 * Information tracked per connected peer.
148 struct ConnectPairInfo
151 * Peer this is about.
153 const struct GNUNET_PeerIdentity *sender;
156 * Information about the receiving peer.
158 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
163 * Function called when we connected two peers. Once we have gotten
164 * to the clique, launch test-specific logic.
166 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
169 connect_cb (void *cls)
171 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
172 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
174 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
178 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
180 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
181 "Peers connected: %u (%s) <-> %u (%s)\n",
185 GNUNET_i2s (&crl->p2->id));
189 if (NULL == ccc->crl_head)
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "All connections UP, launching custom test logic.\n");
193 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
194 ccc->connect_continuation_cls);
200 * Find peer by peer ID.
202 * @param ccc context to search
203 * @param peer peer to look for
204 * @return NULL if @a peer was not found
206 struct GNUNET_TRANSPORT_TESTING_PeerContext *
207 GNUNET_TRANSPORT_TESTING_find_peer (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
208 const struct GNUNET_PeerIdentity *peer)
210 for (unsigned int i=0;i<ccc->num_peers;i++)
211 if ( (NULL != ccc->p[i]) &&
221 * Wrapper around peers connecting. Calls client's nc function.
223 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
224 * @param peer peer we got connected to
225 * @param mq message queue for transmissions to @a peer
226 * @return closure for message handlers
230 const struct GNUNET_PeerIdentity *peer,
231 struct GNUNET_MQ_Handle *mq)
233 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
234 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
235 struct ConnectPairInfo *cpi;
241 cpi = GNUNET_new (struct ConnectPairInfo);
243 cpi->sender = peer; /* valid until disconnect */
249 * Wrapper around peers disconnecting. Calls client's nd function.
251 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
252 * @param peer peer we got disconnected from
253 * @param custom_cls return value from @my_nc
257 const struct GNUNET_PeerIdentity *peer,
260 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
261 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
262 struct ConnectPairInfo *cpi = custom_cls;
273 * Wrapper around receiving data. Calls client's rec function.
275 * @param cls our `struct ConnectPairInfo *`
276 * @param message message we received
277 * @return #GNUNET_OK (all messages are fine)
280 check_test (void *cls,
281 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
288 * Wrapper around receiving data. Calls client's rec function.
290 * @param cls our `struct ConnectPairInfo *`
291 * @param message message we received
294 handle_test (void *cls,
295 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
297 struct ConnectPairInfo *cpi = cls;
298 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
299 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
301 if (NULL != ccc->rec)
310 * Wrapper around receiving data. Calls client's rec function.
312 * @param cls our `struct ConnectPairInfo *`
313 * @param message message we received
314 * @return #GNUNET_OK (all messages are fine)
317 check_test2 (void *cls,
318 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
325 * Wrapper around receiving data. Calls client's rec function.
327 * @param cls our `struct ConnectPairInfo *`
328 * @param message message we received
331 handle_test2 (void *cls,
332 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
334 struct ConnectPairInfo *cpi = cls;
335 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
336 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
338 if (NULL != ccc->rec)
347 * Connect the peers as a clique.
349 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
352 do_connect (void *cls)
354 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
356 ccc->connect_task = NULL;
357 for (unsigned int i=0;i<ccc->num_peers;i++)
358 for (unsigned int j=(ccc->bi_directional ? 0 : i+1);j<ccc->num_peers;j++)
360 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
364 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
365 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
372 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
374 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
375 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
379 GNUNET_i2s (&ccc->p[1]->id));
380 GNUNET_free (sender_c);
382 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
391 * Function called once we have successfully launched a peer.
392 * Once all peers have been launched, we connect all of them
395 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
400 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
401 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
402 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
405 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
406 "Peer %u (`%s') started\n",
408 GNUNET_i2s (&p->id));
409 if (ccc->started != ccc->num_peers)
411 if (NULL != ccc->pre_connect_task)
413 /* Run the custom per-connect job, then give it a second to
414 go into effect before we continue connecting peers. */
415 ccc->pre_connect_task (ccc->pre_connect_task_cls);
416 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
428 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
429 * once the scheduler is up. Should launch the peers and
430 * then in the continuations try to connect them.
432 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
433 * @param args ignored
434 * @param cfgfile ignored
435 * @param cfg configuration
438 connect_check_run (void *cls,
441 const struct GNUNET_CONFIGURATION_Handle *cfg)
443 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
447 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
450 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
453 for (unsigned int i=0;i<ccc->num_peers;i++)
455 struct GNUNET_MQ_MessageHandler handlers[] = {
456 GNUNET_MQ_hd_var_size (test,
457 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
458 struct GNUNET_TRANSPORT_TESTING_TestMessage,
460 GNUNET_MQ_hd_var_size (test2,
461 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
462 struct GNUNET_TRANSPORT_TESTING_TestMessage,
464 GNUNET_MQ_handler_end()
466 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
475 if (NULL == ccc->p[i])
480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
481 "Fail! Could not start peers!\n");
482 GNUNET_SCHEDULER_shutdown ();
488 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
489 * Starts and connects the two peers, then invokes the
490 * `connect_continuation` from @a cls. Sets up a timeout to
491 * abort the test, and a shutdown handler to clean up properly
494 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
495 * @param tth_ initialized testing handle
496 * @param test_plugin_ name of the plugin
497 * @param test_name_ name of the test
498 * @param num_peers number of entries in the @a cfg_file array
499 * @param cfg_files array of names of configuration files for the peers
500 * @return #GNUNET_SYSERR on error
503 GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
504 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
505 const char *test_plugin_,
506 const char *test_name_,
507 unsigned int num_peers,
510 static struct GNUNET_GETOPT_CommandLineOption options[] = {
511 GNUNET_GETOPT_OPTION_END
513 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
514 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
515 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
519 (char *) ccc->config_file,
523 ccc->num_peers = num_peers;
524 ccc->cfg_files = cfg_files;
525 ccc->test_plugin = test_plugin_;
526 ccc->test_name = test_name_;
528 ccc->global_ret = GNUNET_OK;
531 for (unsigned int i=0;i<num_peers;i++)
537 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
544 return GNUNET_SYSERR;
545 return ccc->global_ret;
550 * Setup testcase. Calls @a check with the data the test needs.
552 * @param argv0 binary name (argv[0])
553 * @param filename source file name (__FILE__)
554 * @param num_peers number of peers to start
555 * @param check main function to run
556 * @param check_cls closure for @a check
557 * @return #GNUNET_OK on success
560 GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
561 const char *filename,
562 unsigned int num_peers,
563 GNUNET_TRANSPORT_TESTING_CheckCallback check,
566 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
570 char *cfg_names[num_peers];
574 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
575 GNUNET_log_setup (test_name,
578 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
579 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
581 for (unsigned int i=0;i<num_peers;i++)
582 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
584 tth = GNUNET_TRANSPORT_TESTING_init ();
591 ret = check (check_cls,
597 GNUNET_TRANSPORT_TESTING_done (tth);
599 for (unsigned int i=0;i<num_peers;i++)
600 GNUNET_free (cfg_names[i]);
601 GNUNET_free (test_source);
602 GNUNET_free_non_null (test_plugin);
603 GNUNET_free (test_name);
607 /* end of transport-testing-main.c */