-updating dependency diagram
[oweals/gnunet.git] / src / testing_old / test_testing_topology_churn.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 3, 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_churn.c
22  * @brief base testcase for testing simple churn functionality
23  */
24 #include "platform.h"
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_core_service.h"
27
28
29 /**
30  * How long until we fail the whole testcase?
31  */
32 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
33
34 /**
35  * How long until we give up on starting the peers? (Must be longer than the connect timeout!)
36  */
37 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
38
39 #define DEFAULT_NUM_PEERS 4
40
41 static int ok;
42
43 static unsigned long long num_peers;
44
45 static unsigned int expected_connections;
46
47 static unsigned int expected_failed_connections;
48
49 static unsigned long long peers_left;
50
51 static struct GNUNET_TESTING_PeerGroup *pg;
52
53 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
54
55 GNUNET_SCHEDULER_TaskIdentifier die_task;
56
57 static char *test_directory;
58
59 #define MTYPE 12345
60
61 GNUNET_NETWORK_STRUCT_BEGIN
62
63 struct GNUNET_TestMessage
64 {
65   /**
66    * Header of the message
67    */
68   struct GNUNET_MessageHeader header;
69
70   /**
71    * Unique identifier for this message.
72    */
73   uint32_t uid;
74 };
75 GNUNET_NETWORK_STRUCT_END
76
77 /**
78  * Check whether peers successfully shut down.
79  */
80 void
81 shutdown_callback (void *cls, const char *emsg)
82 {
83   if (emsg != NULL)
84   {
85     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
86     if (ok == 0)
87       ok = 666;
88   }
89   else
90   {
91     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n");
92   }
93 }
94
95 static void
96 finish_testing ()
97 {
98   GNUNET_assert (pg != NULL);
99
100   if (die_task != GNUNET_SCHEDULER_NO_TASK)
101     GNUNET_SCHEDULER_cancel (die_task);
102   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103               "Called finish testing, stopping daemons.\n");
104   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n");
105   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
106   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n");
107   ok = 0;
108 }
109
110 static void
111 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
112 {
113   char *msg = cls;
114
115   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
116               "End badly was called (%s)... stopping daemons.\n", msg);
117
118   if (pg != NULL)
119   {
120     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
121     ok = 7331;                  /* Opposite of leet */
122   }
123   else
124     ok = 401;                   /* Never got peers started */
125
126 }
127
128 struct ChurnTestContext
129 {
130   GNUNET_SCHEDULER_Task next_task;
131
132 };
133
134 static struct ChurnTestContext churn_ctx;
135
136 /**
137  * Churn callback, report on success or failure of churn operation.
138  *
139  * @param cls closure
140  * @param emsg NULL on success
141  */
142 void
143 churn_callback (void *cls, const char *emsg)
144 {
145   if (emsg == NULL)
146   {
147     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n",
148                 emsg);
149     GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL);
150   }
151   else
152   {
153     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
154                 "Failed to churn peers with error `%s'\n", emsg);
155     GNUNET_SCHEDULER_cancel (die_task);
156     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
157   }
158 }
159
160
161 static void
162 churn_peers_both ()
163 {
164   churn_ctx.next_task = &finish_testing;
165   GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL);
166 }
167
168 static void
169 churn_peers_off_again ()
170 {
171   churn_ctx.next_task = &churn_peers_both;
172   GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL);
173 }
174
175 static void
176 churn_peers_on ()
177 {
178   churn_ctx.next_task = &churn_peers_off_again;
179   GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL);
180 }
181
182 static void
183 churn_peers_off ()
184 {
185   churn_ctx.next_task = &churn_peers_on;
186   GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL);
187 }
188
189 static void
190 peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id,
191                         const struct GNUNET_CONFIGURATION_Handle *cfg,
192                         struct GNUNET_TESTING_Daemon *d, const char *emsg)
193 {
194   if (emsg != NULL)
195   {
196     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197                 "Failed to start daemon with error: `%s'\n", emsg);
198     return;
199   }
200   GNUNET_assert (id != NULL);
201   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
202               (num_peers - peers_left) + 1, num_peers);
203   peers_left--;
204   if (peers_left == 0)
205   {
206     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207                 "All %d daemons started, now testing churn!\n", num_peers);
208     GNUNET_SCHEDULER_cancel (die_task);
209     /* Set up task in case topology creation doesn't finish
210      * within a reasonable amount of time */
211     die_task =
212         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
213                                       (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly,
214                                       "from peers_started_callback");
215     churn_peers_off ();
216     ok = 0;
217   }
218 }
219
220
221 static void
222 run (void *cls, char *const *args, const char *cfgfile,
223      const struct GNUNET_CONFIGURATION_Handle *cfg)
224 {
225   ok = 1;
226
227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228               "Starting daemons based on config file %s\n", cfgfile);
229   if (GNUNET_YES !=
230       GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
231                                              &test_directory))
232   {
233     ok = 404;
234     return;
235   }
236
237   if (GNUNET_SYSERR ==
238       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
239                                              &num_peers))
240     num_peers = DEFAULT_NUM_PEERS;
241
242   main_cfg = cfg;
243
244   peers_left = num_peers;
245   GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1);
246
247   /* For this specific test we only really want a CLIQUE topology as the
248    * overlay allowed topology, and a RING topology as the underlying connection
249    * allowed topology.  So we will expect only num_peers * 2 connections to
250    * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail.
251    */
252   expected_connections = num_peers * (num_peers - 1);
253   expected_failed_connections = expected_connections - (num_peers * 2);
254
255
256   /* Set up a task to end testing if peer start fails */
257   die_task =
258       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
259                                     (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly,
260                                     "didn't start all daemons in reasonable amount of time!!!");
261
262   pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left,
263                                      TIMEOUT, NULL, NULL,
264                                      &peers_started_callback, NULL, NULL, NULL,
265                                      NULL);
266
267 }
268
269 static int
270 check ()
271 {
272   int ret;
273
274   char *const argv[] = { "test-testing-topology-churn",
275     "-c",
276     "test_testing_data_topology_churn.conf",
277     NULL
278   };
279   struct GNUNET_GETOPT_CommandLineOption options[] = {
280     GNUNET_GETOPT_OPTION_END
281   };
282   ret =
283       GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
284                           "test-testing-topology-churn", "nohelp", options,
285                           &run, &ok);
286   if (ret != GNUNET_OK)
287   {
288     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
289                 "`test-testing-topology-churn': Failed with error code %d\n",
290                 ret);
291   }
292
293   return ok;
294 }
295
296 int
297 main (int argc, char *argv[])
298 {
299   int ret;
300
301   GNUNET_log_setup ("test_testing_topology_churn",
302                     "WARNING",
303                     NULL);
304   ret = check ();
305
306   /**
307    * Need to remove base directory, subdirectories taken care
308    * of by the testing framework.
309    */
310   if (test_directory != NULL)
311   {
312     if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
313     {
314       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315                   "Failed to remove testing directory %s\n", test_directory);
316     }
317   }
318
319   return ret;
320 }
321
322 /* end of test_testing_topology_churn.c */