twopeer dht test, mostly for class
[oweals/gnunet.git] / src / dht / test_dht_twopeer.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 dht/test_dht_twopeer.c
22  * @brief base testcase for testing DHT service with
23  *        two running peers
24  */
25 #include "platform.h"
26 #include "gnunet_testing_lib.h"
27 #include "gnunet_core_service.h"
28 #include "gnunet_dht_service.h"
29
30 /* DEFINES */
31 #define VERBOSE GNUNET_YES
32
33 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
34
35 #define DEFAULT_NUM_PEERS 2
36
37 /* Structs */
38 /* ... */
39
40 /* Globals */
41 static char *test_directory;
42
43 static unsigned int expected_connections;
44
45 static unsigned long long peers_left;
46
47 static struct GNUNET_TESTING_PeerGroup *pg;
48
49 static struct GNUNET_SCHEDULER_Handle *sched;
50
51 static unsigned long long num_peers;
52
53 static unsigned int total_connections;
54
55 static unsigned int failed_connections;
56
57 GNUNET_SCHEDULER_TaskIdentifier die_task;
58
59 static int ok;
60
61 /**
62  * Check whether peers successfully shut down.
63  */
64 void shutdown_callback (void *cls,
65                         const char *emsg)
66 {
67   if (emsg != NULL)
68     {
69       if (ok == 0)
70         ok = 2;
71     }
72 }
73
74 static void
75 finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
76 {
77   GNUNET_assert (pg != NULL);
78   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
79   ok = 0;
80 }
81
82 static void
83 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
84 {
85   if (pg != NULL)
86     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
87   ok = 1;
88 }
89
90 void
91 topology_callback (void *cls,
92                    const struct GNUNET_PeerIdentity *first,
93                    const struct GNUNET_PeerIdentity *second,
94                    uint32_t distance,
95                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
96                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
97                    struct GNUNET_TESTING_Daemon *first_daemon,
98                    struct GNUNET_TESTING_Daemon *second_daemon,
99                    const char *emsg)
100 {
101   if (emsg == NULL)
102     {
103       total_connections++;
104 #if VERBOSE
105       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
106                  first_daemon->shortname,
107                  second_daemon->shortname,
108                  distance);
109 #endif
110     }
111 #if VERBOSE
112   else
113     {
114       failed_connections++;
115       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
116                   first_daemon->shortname,
117                   second_daemon->shortname, emsg);
118     }
119 #endif
120
121   if (total_connections == expected_connections)
122     {
123 #if VERBOSE
124       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
125                   "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
126                   total_connections);
127 #endif
128       GNUNET_SCHEDULER_cancel (sched, die_task);
129       die_task = GNUNET_SCHEDULER_NO_TASK;
130       //GNUNET_SCHEDULER_add_now (sched, &next_phase, NULL);
131       GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
132     }
133   else if (total_connections + failed_connections == expected_connections)
134     {
135       GNUNET_SCHEDULER_cancel (sched, die_task);
136       die_task = GNUNET_SCHEDULER_add_now (sched,
137                                                &end_badly, "from topology_callback (too many failed connections)");
138     }
139   else
140     {
141 #if VERBOSE
142       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143                   "Have %d total connections, %d failed connections, Want %d\n",
144                   total_connections, failed_connections, expected_connections);
145 #endif
146     }
147 }
148
149 static void
150 connect_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
151 {
152   expected_connections = -1;
153   if ((pg != NULL) && (peers_left == 0))
154     {
155       expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0);
156 #if VERBOSE
157       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158                   "Have %d expected connections\n", expected_connections);
159 #endif
160     }
161
162   GNUNET_SCHEDULER_cancel (sched, die_task);
163   if (expected_connections == GNUNET_SYSERR)
164     {
165       die_task = GNUNET_SCHEDULER_add_now (sched,
166                                            &end_badly, "from connect topology (bad return)");
167     }
168
169   die_task = GNUNET_SCHEDULER_add_delayed (sched,
170                                            TIMEOUT,
171                                            &end_badly, "from connect topology (timeout)");
172 }
173
174 static void
175 peers_started_callback (void *cls,
176        const struct GNUNET_PeerIdentity *id,
177        const struct GNUNET_CONFIGURATION_Handle *cfg,
178        struct GNUNET_TESTING_Daemon *d, const char *emsg)
179 {
180   if (emsg != NULL)
181     {
182       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
183                   emsg);
184       return;
185     }
186   GNUNET_assert (id != NULL);
187 #if VERBOSE
188   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
189               (num_peers - peers_left) + 1, num_peers);
190 #endif
191
192   //GNUNET_DHT_connect();
193   peers_left--;
194
195   if (peers_left == 0)
196     {
197 #if VERBOSE
198       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
199                   "All %d daemons started, now creating topology!\n",
200                   num_peers);
201 #endif
202       GNUNET_SCHEDULER_cancel (sched, die_task);
203       /* Set up task in case topology creation doesn't finish
204        * within a reasonable amount of time */
205       die_task = GNUNET_SCHEDULER_add_delayed (sched,
206                                                GNUNET_TIME_relative_multiply
207                                                (GNUNET_TIME_UNIT_MINUTES, 5),
208                                                &end_badly, "from peers_started_callback");
209
210       GNUNET_SCHEDULER_add_now(sched, &connect_topology, NULL);
211       ok = 0;
212     }
213 }
214
215 static void
216 run (void *cls,
217      struct GNUNET_SCHEDULER_Handle *s,
218      char *const *args,
219      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
220 {
221   sched = s;
222   ok = 1;
223
224   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
225     {
226       ok = 404;
227       return;
228     }
229
230   if (GNUNET_SYSERR ==
231       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
232                                              &num_peers))
233     num_peers = DEFAULT_NUM_PEERS;
234
235   peers_left = num_peers;
236
237   /* Set up a task to end testing if peer start fails */
238   die_task = GNUNET_SCHEDULER_add_delayed (sched,
239                                            TIMEOUT,
240                                            &end_badly, "didn't start all daemons in reasonable amount of time!!!");
241
242   pg = GNUNET_TESTING_daemons_start (sched, cfg,
243                                      num_peers, TIMEOUT, NULL, NULL, &peers_started_callback, NULL,
244                                      &topology_callback, NULL, NULL);
245
246 }
247
248 static int
249 check ()
250 {
251   int ret;
252   char *const argv[] = {"test-dht-twopeer",
253     "-c",
254     "test_dht_twopeer_data.conf",
255 #if VERBOSE
256     "-L", "DEBUG",
257 #endif
258     NULL
259   };
260   struct GNUNET_GETOPT_CommandLineOption options[] = {
261     GNUNET_GETOPT_OPTION_END
262   };
263   ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
264                       argv, "test-dht-twopeer", "nohelp",
265                       options, &run, &ok);
266   if (ret != GNUNET_OK)
267     {
268       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret);
269     }
270   return ok;
271 }
272
273 int
274 main (int argc, char *argv[])
275 {
276   int ret;
277
278   GNUNET_log_setup ("test-dht-twopeer",
279 #if VERBOSE
280                     "DEBUG",
281 #else
282                     "WARNING",
283 #endif
284                     NULL);
285   ret = check ();
286   /**
287    * Need to remove base directory, subdirectories taken care
288    * of by the testing framework.
289    */
290   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
291     {
292       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
293     }
294   return ret;
295 }
296
297 /* end of test_dht_twopeer.c */