enable more verbose logging to debug on buildbots
[oweals/gnunet.git] / src / testing / test_testing_topology.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
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 2, or (at your
8      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      General Public License for more details.
14
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file testing/test_testing_topology.c
22  * @brief base testcase for testing all the topologies provided
23  */
24 #include "platform.h"
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_core_service.h"
27
28 #define VERBOSE GNUNET_YES
29
30 /**
31  * How long until we fail the whole testcase?
32  */
33 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
34
35 /**
36  * How long until we give up on connecting the peers?
37  */
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
39
40 #define DEFAULT_NUM_PEERS 4
41
42 #define MAX_OUTSTANDING_CONNECTIONS 300
43
44 static float fail_percentage = 0.05;
45
46 static int ok;
47
48 static unsigned long long num_peers;
49
50 static unsigned int total_connections;
51
52 static unsigned int failed_connections;
53
54 static unsigned int total_server_connections;
55
56 static unsigned int total_messages_received;
57
58 static unsigned int expected_messages;
59
60 static unsigned int expected_connections;
61
62 static unsigned long long peers_left;
63
64 static struct GNUNET_TESTING_PeerGroup *pg;
65
66 static struct GNUNET_SCHEDULER_Handle *sched;
67
68 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
69
70 GNUNET_SCHEDULER_TaskIdentifier die_task;
71
72 static char *dotOutFileName;
73
74 static FILE *dotOutFile;
75
76 static char *topology_string;
77
78 static int transmit_ready_scheduled;
79
80 static int transmit_ready_failed;
81
82 static int transmit_ready_called;
83
84 static enum GNUNET_TESTING_Topology topology;
85
86 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */
87
88 static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
89
90 static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
91
92 static double connect_topology_option_modifier = 0.0;
93
94 static char *test_directory;
95
96 #define MTYPE 12345
97
98 struct GNUNET_TestMessage
99 {
100   /**
101    * Header of the message
102    */
103   struct GNUNET_MessageHeader header;
104
105   /**
106    * Unique identifier for this message.
107    */
108   uint32_t uid;
109 };
110
111 struct TestMessageContext
112 {
113   /* This is a linked list */
114   struct TestMessageContext *next;
115
116   /* Handle to the sending peer core */
117   struct GNUNET_CORE_Handle *peer1handle;
118
119   /* Handle to the receiving peer core */
120   struct GNUNET_CORE_Handle *peer2handle;
121
122   /* Handle to the sending peer daemon */
123   struct GNUNET_TESTING_Daemon *peer1;
124
125   /* Handle to the receiving peer daemon */
126   struct GNUNET_TESTING_Daemon *peer2;
127
128   /* Identifier for this message, so we don't disconnect other peers! */
129   uint32_t uid;
130
131   /* Task for disconnecting cores, allow task to be cancelled on shutdown */
132   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
133
134 };
135
136 static struct TestMessageContext *test_messages;
137
138 static void
139 finish_testing ()
140 {
141   GNUNET_assert (pg != NULL);
142   struct TestMessageContext *pos;
143   struct TestMessageContext *free_pos;
144 #if VERBOSE
145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146               "Called finish testing, stopping daemons.\n");
147 #endif
148   int count;
149   count = 0;
150   pos = test_messages;
151   while (pos != NULL)
152     {
153       if (pos->peer1handle != NULL)
154         {
155           GNUNET_CORE_disconnect(pos->peer1handle);
156           pos->peer1handle = NULL;
157         }
158       if (pos->peer2handle != NULL)
159         {
160           GNUNET_CORE_disconnect(pos->peer2handle);
161           pos->peer2handle = NULL;
162         }
163       free_pos = pos;
164       pos = pos->next;
165       if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
166         {
167           GNUNET_SCHEDULER_cancel(sched, free_pos->disconnect_task);
168         }
169       GNUNET_free(free_pos);
170     }
171 #if VERBOSE
172           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173                       "transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called);
174 #endif
175   sleep(1);
176 #if VERBOSE
177           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178                       "Calling daemons_stop\n");
179 #endif
180   GNUNET_TESTING_daemons_stop (pg);
181 #if VERBOSE
182           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
183                       "daemons_stop finished\n");
184 #endif
185   if (dotOutFile != NULL)
186     {
187       fprintf(dotOutFile, "}");
188       fclose(dotOutFile);
189     }
190
191   ok = 0;
192 }
193
194
195 static void
196 disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
197 {
198   struct TestMessageContext *pos = cls;
199
200   /* Disconnect from the respective cores */
201 #if VERBOSE
202   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203               "Disconnecting from peer 1 `%4s'\n", GNUNET_i2s (&pos->peer1->id));
204 #endif
205   if (pos->peer1handle != NULL)
206     GNUNET_CORE_disconnect(pos->peer1handle);
207 #if VERBOSE
208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
209               "Disconnecting from peer 2 `%4s'\n", GNUNET_i2s (&pos->peer2->id));
210 #endif
211   if (pos->peer2handle != NULL)
212     GNUNET_CORE_disconnect(pos->peer2handle);
213   /* Set handles to NULL so test case can be ended properly */
214   pos->peer1handle = NULL;
215   pos->peer2handle = NULL;
216   pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
217   /* Decrement total connections so new can be established */
218   total_server_connections -= 2;
219 }
220
221 static int
222 process_mtype (void *cls,
223                const struct GNUNET_PeerIdentity *peer,
224                const struct GNUNET_MessageHeader *message,
225                struct GNUNET_TIME_Relative latency,
226                uint32_t distance)
227 {
228   struct TestMessageContext *pos = cls;
229   struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *)message;
230   if (pos->uid != ntohl(msg->uid))
231     return GNUNET_OK;
232
233   total_messages_received++;
234 #if VERBOSE
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236               "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), ntohs(message->type));
237   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238               "Total messages received %d, expected %d.\n", total_messages_received, expected_messages);
239 #endif
240
241   if (total_messages_received == expected_messages)
242     {
243       GNUNET_SCHEDULER_cancel (sched, die_task);
244       GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
245     }
246   else
247     {
248       pos->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &disconnect_cores, pos);
249     }
250
251   return GNUNET_OK;
252 }
253
254 static void
255 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
256 {
257   char *msg = cls;
258   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
259               "End badly was called (%s)... stopping daemons.\n", msg);
260   struct TestMessageContext *pos;
261   struct TestMessageContext *free_pos;
262
263   pos = test_messages;
264   while (pos != NULL)
265     {
266       if (pos->peer1handle != NULL)
267         {
268           GNUNET_CORE_disconnect(pos->peer1handle);
269           pos->peer1handle = NULL;
270         }
271       if (pos->peer2handle != NULL)
272         {
273           GNUNET_CORE_disconnect(pos->peer2handle);
274           pos->peer2handle = NULL;
275         }
276       free_pos = pos;
277       pos = pos->next;
278       GNUNET_free(free_pos);
279     }
280
281   if (pg != NULL)
282     {
283       GNUNET_TESTING_daemons_stop (pg);
284       ok = 7331;                /* Opposite of leet */
285     }
286   else
287     ok = 401;                   /* Never got peers started */
288
289   if (dotOutFile != NULL)
290     {
291       fprintf(dotOutFile, "}");
292       fclose(dotOutFile);
293     }
294 }
295
296
297
298 static size_t
299 transmit_ready (void *cls, size_t size, void *buf)
300 {
301   struct GNUNET_TestMessage *m;
302   struct TestMessageContext *pos = cls;
303
304   GNUNET_assert (buf != NULL);
305   m = (struct GNUNET_TestMessage *) buf;
306   m->header.type = htons (MTYPE);
307   m->header.size = htons (sizeof (struct GNUNET_TestMessage));
308   m->uid = htonl(pos->uid);
309   transmit_ready_called++;
310 #if VERBOSE
311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
312               "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s(&pos->peer1->id), transmit_ready_scheduled, transmit_ready_called);
313 #endif
314   return sizeof (struct GNUNET_TestMessage);
315 }
316
317
318 static struct GNUNET_CORE_MessageHandler no_handlers[] = {
319   {NULL, 0, 0}
320 };
321
322 static struct GNUNET_CORE_MessageHandler handlers[] = {
323   {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)},
324   {NULL, 0, 0}
325 };
326
327 static void
328 init_notify_peer2 (void *cls,
329              struct GNUNET_CORE_Handle *server,
330              const struct GNUNET_PeerIdentity *my_identity,
331              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
332 {
333   struct TestMessageContext *pos = cls;
334
335 #if VERBOSE
336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337               "Core connection to `%4s' established, scheduling message send\n",
338               GNUNET_i2s (my_identity));
339 #endif
340   total_server_connections++;
341
342   if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle,
343                                                  0,
344                                                  TIMEOUT,
345                                                  &pos->peer2->id,
346                                                  sizeof (struct GNUNET_TestMessage),
347                                                  &transmit_ready, pos))
348     {
349       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
350                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
351                   GNUNET_i2s (&pos->peer2->id));
352       transmit_ready_failed++;
353     }
354   else
355     {
356       transmit_ready_scheduled++;
357     }
358 }
359
360
361 static void
362 init_notify_peer1 (void *cls,
363              struct GNUNET_CORE_Handle *server,
364              const struct GNUNET_PeerIdentity *my_identity,
365              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
366 {
367   struct TestMessageContext *pos = cls;
368   total_server_connections++;
369
370 #if VERBOSE
371   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372               "Core connection to `%4s' established, setting up handles\n",
373               GNUNET_i2s (my_identity));
374 #endif
375
376   /*
377    * Connect to the receiving peer
378    */
379   pos->peer2handle = GNUNET_CORE_connect (sched,
380                        pos->peer2->cfg,
381                        TIMEOUT,
382                        pos,
383                        &init_notify_peer2,
384                        NULL,
385                        NULL,
386                        NULL,
387                        GNUNET_YES, NULL, GNUNET_YES, handlers);
388
389 }
390
391
392 static void
393 send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
394 {
395   struct TestMessageContext *pos = cls;
396
397   if ((tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) || (cls == NULL))
398     return;
399
400   if (die_task == GNUNET_SCHEDULER_NO_TASK)
401     {
402       die_task = GNUNET_SCHEDULER_add_delayed (sched,
403                                                TEST_TIMEOUT,
404                                                &end_badly, "from create topology (timeout)");
405     }
406
407   if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS)
408     {
409       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
410                                     &send_test_messages, pos);
411       return; /* Otherwise we'll double schedule messages here! */
412     }
413
414   /*
415    * Connect to the sending peer
416    */
417   pos->peer1handle = GNUNET_CORE_connect (sched,
418                                           pos->peer1->cfg,
419                                           TIMEOUT,
420                                           pos,
421                                           &init_notify_peer1,
422                                           NULL,
423                                           NULL,
424                                           NULL,
425                                           GNUNET_NO, NULL, GNUNET_NO, no_handlers);
426
427   GNUNET_assert(pos->peer1handle != NULL);
428
429   if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS)
430     {
431       GNUNET_SCHEDULER_add_now (sched,
432                                 &send_test_messages, pos->next);
433     }
434   else
435     {
436       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
437                                     &send_test_messages, pos->next);
438     }
439 }
440
441
442 void
443 topology_callback (void *cls,
444                    const struct GNUNET_PeerIdentity *first,
445                    const struct GNUNET_PeerIdentity *second,
446                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
447                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
448                    struct GNUNET_TESTING_Daemon *first_daemon,
449                    struct GNUNET_TESTING_Daemon *second_daemon,
450                    const char *emsg)
451 {
452   struct TestMessageContext *temp_context;
453   if (emsg == NULL)
454     {
455       total_connections++;
456 #if VERBOSE
457       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
458                first_daemon->shortname,
459                second_daemon->shortname);
460 #endif
461       temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
462       temp_context->peer1 = first_daemon;
463       temp_context->peer2 = second_daemon;
464       temp_context->next = test_messages;
465       temp_context->uid = total_connections;
466       temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
467       test_messages = temp_context;
468
469       expected_messages++;
470       if (dotOutFile != NULL)
471         fprintf(dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname);
472     }
473 #if VERBOSE
474   else
475     {
476       failed_connections++;
477       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
478                first_daemon->shortname,
479                second_daemon->shortname, emsg);
480     }
481 #endif
482
483   if (total_connections == expected_connections)
484     {
485 #if VERBOSE
486       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487                   "Created %d total connections, which is our target number!  Calling send messages.\n",
488                   total_connections);
489 #endif
490
491       GNUNET_SCHEDULER_cancel (sched, die_task);
492       die_task = GNUNET_SCHEDULER_NO_TASK;
493       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, test_messages);
494     }
495   else if (total_connections + failed_connections == expected_connections)
496     {
497       if (failed_connections < (unsigned int)(fail_percentage * total_connections))
498         {
499           GNUNET_SCHEDULER_cancel (sched, die_task);
500           die_task = GNUNET_SCHEDULER_NO_TASK;
501           GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, test_messages);
502         }
503       else
504         {
505           GNUNET_SCHEDULER_cancel (sched, die_task);
506           die_task = GNUNET_SCHEDULER_add_now (sched,
507                                                &end_badly, "from topology_callback (too many failed connections)");
508         }
509     }
510   else
511     {
512 #if VERBOSE
513       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
514                   "Have %d total connections, %d failed connections, Want %d (at least %d)\n",
515                   total_connections, failed_connections, expected_connections, expected_connections - (unsigned int)(fail_percentage * expected_connections));
516 #endif
517     }
518 }
519
520 static void
521 connect_topology ()
522 {
523   expected_connections = -1;
524   if ((pg != NULL) && (peers_left == 0))
525     {
526       expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier);
527 #if VERBOSE
528       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529                   "Have %d expected connections\n", expected_connections);
530 #endif
531     }
532
533   GNUNET_SCHEDULER_cancel (sched, die_task);
534   if (expected_connections == GNUNET_SYSERR)
535     {
536       die_task = GNUNET_SCHEDULER_add_now (sched,
537                                            &end_badly, "from connect topology (bad return)");
538     }
539
540   die_task = GNUNET_SCHEDULER_add_delayed (sched,
541                                            TEST_TIMEOUT,
542                                            &end_badly, "from connect topology (timeout)");
543 }
544
545 static void
546 create_topology ()
547 {
548   peers_left = num_peers; /* Reset counter */
549   if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology) != GNUNET_SYSERR)
550     {
551 #if VERBOSE
552       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553                   "Topology set up, now starting peers!\n");
554 #endif
555       GNUNET_TESTING_daemons_continue_startup(pg);
556     }
557   else
558     {
559       GNUNET_SCHEDULER_cancel (sched, die_task);
560       die_task = GNUNET_SCHEDULER_add_now (sched,
561                                            &end_badly, "from create topology (bad return)");
562     }
563   GNUNET_SCHEDULER_cancel (sched, die_task);
564   die_task = GNUNET_SCHEDULER_add_delayed (sched,
565                                            TEST_TIMEOUT,
566                                            &end_badly, "from continue startup (timeout)");
567 }
568
569
570 static void
571 peers_started_callback (void *cls,
572        const struct GNUNET_PeerIdentity *id,
573        const struct GNUNET_CONFIGURATION_Handle *cfg,
574        struct GNUNET_TESTING_Daemon *d, const char *emsg)
575 {
576   if (emsg != NULL)
577     {
578       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
579                   emsg);
580       return;
581     }
582   GNUNET_assert (id != NULL);
583 #if VERBOSE
584   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
585               (num_peers - peers_left) + 1, num_peers);
586 #endif
587   peers_left--;
588   if (peers_left == 0)
589     {
590 #if VERBOSE
591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592                   "All %d daemons started, now creating topology!\n",
593                   num_peers);
594 #endif
595       GNUNET_SCHEDULER_cancel (sched, die_task);
596       /* Set up task in case topology creation doesn't finish
597        * within a reasonable amount of time */
598       die_task = GNUNET_SCHEDULER_add_delayed (sched,
599                                                GNUNET_TIME_relative_multiply
600                                                (GNUNET_TIME_UNIT_MINUTES, 5),
601                                                &end_badly, "from peers_started_callback");
602       connect_topology ();
603       ok = 0;
604     }
605 }
606
607 /**
608  * Callback indicating that the hostkey was created for a peer.
609  *
610  * @param cls NULL
611  * @param id the peer identity
612  * @param d the daemon handle (pretty useless at this point, remove?)
613  * @param emsg non-null on failure
614  */
615 void hostkey_callback (void *cls,
616                        const struct GNUNET_PeerIdentity *id,
617                        struct GNUNET_TESTING_Daemon *d,
618                        const char *emsg)
619 {
620   if (emsg != NULL)
621     {
622       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg);
623     }
624
625 #if VERBOSE
626     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
627                 "Hostkey created for peer `%s'\n",
628                 GNUNET_i2s(id));
629 #endif
630     peers_left--;
631     if (peers_left == 0)
632       {
633 #if VERBOSE
634         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635                     "All %d hostkeys created, now creating topology!\n",
636                     num_peers);
637 #endif
638         GNUNET_SCHEDULER_cancel (sched, die_task);
639         /* Set up task in case topology creation doesn't finish
640          * within a reasonable amount of time */
641         die_task = GNUNET_SCHEDULER_add_delayed (sched,
642                                                  GNUNET_TIME_relative_multiply
643                                                  (GNUNET_TIME_UNIT_MINUTES, 5),
644                                                  &end_badly, "from hostkey_callback");
645         GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL);
646         ok = 0;
647       }
648 }
649
650 static void
651 run (void *cls,
652      struct GNUNET_SCHEDULER_Handle *s,
653      char *const *args,
654      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
655 {
656   unsigned long long topology_num;
657   unsigned long long connect_topology_num;
658   unsigned long long blacklist_topology_num;
659   unsigned long long connect_topology_option_num;
660   char *connect_topology_option_modifier_string;
661   sched = s;
662   ok = 1;
663
664   dotOutFile = fopen (dotOutFileName, "w");
665   if (dotOutFile != NULL)
666     {
667       fprintf (dotOutFile, "strict graph G {\n");
668     }
669
670 #if VERBOSE
671   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672               "Starting daemons based on config file %s\n", cfgfile);
673 #endif
674
675   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
676     {
677       ok = 404;
678       return;
679     }
680
681   if (GNUNET_YES ==
682       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology",
683                                              &topology_num))
684     topology = topology_num;
685
686   if (GNUNET_YES ==
687       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology",
688                                              &connect_topology_num))
689     connection_topology = connect_topology_num;
690
691   if (GNUNET_YES ==
692         GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology_option",
693                                                &connect_topology_option_num))
694     connect_topology_option = connect_topology_option_num;
695
696   if (GNUNET_YES ==
697         GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier",
698                                                &connect_topology_option_modifier_string))
699     {
700       if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1)
701       {
702         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
703         _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
704         connect_topology_option_modifier_string,
705         "connect_topology_option_modifier",
706         "TESTING");
707         GNUNET_free (connect_topology_option_modifier_string);
708       }
709     }
710
711   if (GNUNET_YES ==
712       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "blacklist_topology",
713                                              &blacklist_topology_num))
714     blacklist_topology = blacklist_topology_num;
715
716   if (GNUNET_SYSERR ==
717       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
718                                              &num_peers))
719     num_peers = DEFAULT_NUM_PEERS;
720
721   main_cfg = cfg;
722
723   peers_left = num_peers;
724
725   /* Set up a task to end testing if peer start fails */
726   die_task = GNUNET_SCHEDULER_add_delayed (sched,
727                                            GNUNET_TIME_relative_multiply
728                                            (GNUNET_TIME_UNIT_MINUTES, 5),
729                                            &end_badly, "didn't start all daemons in reasonable amount of time!!!");
730
731   pg = GNUNET_TESTING_daemons_start (sched, cfg,
732                                      peers_left, &hostkey_callback, NULL, &peers_started_callback, NULL,
733                                      &topology_callback, NULL, NULL);
734
735 }
736
737 static int
738 check ()
739 {
740   char *binary_name;
741   char *config_file_name;
742   GNUNET_asprintf(&binary_name, "test-testing-topology-%s", topology_string);
743   GNUNET_asprintf(&config_file_name, "test_testing_data_topology_%s.conf", topology_string);
744   int ret;
745   char *const argv[] = {binary_name,
746     "-c",
747     config_file_name,
748 #if VERBOSE
749     "-L", "DEBUG",
750 #endif
751     NULL
752   };
753   struct GNUNET_GETOPT_CommandLineOption options[] = {
754     GNUNET_GETOPT_OPTION_END
755   };
756   ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
757                       argv, binary_name, "nohelp",
758                       options, &run, &ok);
759   if (ret != GNUNET_OK)
760     {
761       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-testing-topology-%s': Failed with error code %d\n", topology_string, ret);
762     }
763   GNUNET_free(binary_name);
764   GNUNET_free(config_file_name);
765   return ok;
766 }
767
768 int
769 main (int argc, char *argv[])
770 {
771   int ret;
772   char *binary_start_pos;
773   char *our_binary_name;
774
775   binary_start_pos = rindex(argv[0], '/');
776   topology_string = strstr (binary_start_pos,
777                             "_topology");
778   GNUNET_assert (topology_string != NULL);
779   topology_string++;
780   topology_string = strstr (topology_string, "_");
781   GNUNET_assert (topology_string != NULL);
782   topology_string++;
783
784   GNUNET_asprintf(&our_binary_name, "test-testing-topology_%s", topology_string);
785   GNUNET_asprintf(&dotOutFileName, "topology_%s.dot", topology_string);
786
787   GNUNET_log_setup (our_binary_name,
788 #if VERBOSE
789                     "DEBUG",
790 #else
791                     "WARNING",
792 #endif
793                     NULL);
794   ret = check ();
795
796   /**
797    * Need to remove base directory, subdirectories taken care
798    * of by the testing framework.
799    */
800   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
801     {
802       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
803     }
804   GNUNET_free(our_binary_name);
805   return ret;
806 }
807
808 /* end of test_testing_group.c */