86a78acbaf24ce216afcd411a77024eee8b427cd
[oweals/gnunet.git] / src / testbed / test_testbed_api_2peers_1controller.c
1 /*
2       This file is part of GNUnet
3       (C) 2008--2012 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 /**
22  * @file testbed/test_testbed_api_2peers_1controller.c
23  * @brief testcases for the testbed api: 2 peers are configured, started and
24  *          connected together. The 2 peer reside on a single controller.
25  * @author Sree Harsha Totakura
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testing_lib-new.h"
31 #include "gnunet_testbed_service.h"
32
33
34 /**
35  * Generic logging shortcut
36  */
37 #define LOG(kind,...)                           \
38   GNUNET_log (kind, __VA_ARGS__)
39
40 /**
41  * Relative time seconds shorthand
42  */
43 #define TIME_REL_SECS(sec) \
44   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46 /**
47  * Peer context
48  */
49 struct PeerContext
50 {
51   /**
52    * The peer handle
53    */
54   struct GNUNET_TESTBED_Peer *peer;
55
56   /**
57    * Operations involving this peer
58    */
59   struct GNUNET_TESTBED_Operation *operation;
60
61   /**
62    * set to GNUNET_YES when peer is started
63    */
64   int is_running;
65 };
66
67 /**
68  * Our localhost
69  */
70 static struct GNUNET_TESTBED_Host *host;
71
72 /**
73  * The controller process
74  */
75 static struct GNUNET_TESTBED_ControllerProc *cp;
76
77 /**
78  * The controller handle
79  */
80 static struct GNUNET_TESTBED_Controller *controller;
81
82 /**
83  * A neighbouring host
84  */
85 static struct GNUNET_TESTBED_Host *neighbour;
86
87 /**
88  * Handle for neighbour registration
89  */
90 static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
91
92 /**
93  * peer 1
94  */
95 static struct PeerContext peer1;
96
97 /**
98  * peer2
99  */
100 static struct PeerContext peer2;
101
102 /**
103  * Handle to configuration
104  */
105 static struct GNUNET_CONFIGURATION_Handle *cfg;
106
107 /**
108  * Handle to operations involving both peers
109  */
110 static struct GNUNET_TESTBED_Operation *common_operation;
111
112 /**
113  * Abort task identifier
114  */
115 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
116
117 /**
118  * Delayed connect job identifier
119  */
120 static GNUNET_SCHEDULER_TaskIdentifier delayed_connect_task;
121
122 /**
123  * Different stages in testing
124  */
125 enum Stage
126 {
127
128   /**
129    * Initial stage
130    */
131   INIT,
132
133   /**
134    * peers are created
135    */
136   PEERS_CREATED,
137
138   /**
139    * peers are started
140    */
141   PEERS_STARTED,
142
143   /**
144    * peers are connected
145    */
146   PEERS_CONNECTED,
147
148   /**
149    * Peers are connected once again (this should not fail as they are already connected)
150    */
151   PEERS_CONNECTED_2,
152
153   /**
154    * peers are stopped
155    */
156   PEERS_STOPPED,
157
158   /**
159    * Final success stage
160    */
161   SUCCESS
162 };
163
164 /**
165  * The testing result
166  */
167 static enum Stage result;
168
169 /**
170  * shortcut to exit during failure
171  */
172 #define FAIL_TEST(cond) do {                                    \
173     if (!(cond)) {                                              \
174       GNUNET_break(0);                                          \
175       if (GNUNET_SCHEDULER_NO_TASK != abort_task)               \
176         GNUNET_SCHEDULER_cancel (abort_task);                   \
177       abort_task = GNUNET_SCHEDULER_NO_TASK;                    \
178       GNUNET_SCHEDULER_add_now (do_shutdown, NULL);             \
179       exit (1);                                                 \
180     }                                                           \
181   } while (0)
182
183 /**
184  * Shutdown nicely
185  *
186  * @param cls NULL
187  * @param tc the task context
188  */
189 static void
190 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
191 {
192   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
193     GNUNET_SCHEDULER_cancel (abort_task);
194   if (GNUNET_SCHEDULER_NO_TASK != delayed_connect_task)
195     GNUNET_SCHEDULER_cancel (delayed_connect_task);
196   if (NULL != reg_handle)
197     GNUNET_TESTBED_cancel_registration (reg_handle);
198   GNUNET_TESTBED_controller_disconnect (controller);
199   GNUNET_CONFIGURATION_destroy (cfg);
200   if (NULL != cp)
201     GNUNET_TESTBED_controller_stop (cp);
202   GNUNET_TESTBED_host_destroy (neighbour);
203   GNUNET_TESTBED_host_destroy (host);
204 }
205
206
207 /**
208  * abort task to run on test timed out
209  *
210  * @param cls NULL
211  * @param tc the task context
212  */
213 static void
214 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
215 {
216   LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
217   abort_task = GNUNET_SCHEDULER_NO_TASK;
218   do_shutdown (cls, tc);
219 }
220
221
222 /**
223  * Callback to be called when an operation is completed
224  *
225  * @param cls the callback closure from functions generating an operation
226  * @param op the operation that has been finished
227  * @param emsg error message in case the operation has failed; will be NULL if
228  *          operation has executed successfully.
229  */
230 static void 
231 op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
232
233
234 /**
235  * task for delaying a connect
236  *
237  * @param cls NULL
238  * @param tc the task context
239  */
240 static void
241 do_delayed_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
242 {
243   delayed_connect_task = GNUNET_SCHEDULER_NO_TASK;
244   FAIL_TEST (NULL == common_operation);
245   common_operation = GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, 
246                                                      peer1.peer, peer2.peer);
247 }
248
249
250 /**
251  * Callback to be called when an operation is completed
252  *
253  * @param cls the callback closure from functions generating an operation
254  * @param op the operation that has been finished
255  * @param emsg error message in case the operation has failed; will be NULL if
256  *          operation has executed successfully.
257  */
258 static void 
259 op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
260 {
261   FAIL_TEST (common_operation == op);
262   switch(result)
263   {
264   case PEERS_STARTED:
265     FAIL_TEST (NULL == peer1.operation);
266     FAIL_TEST (NULL == peer2.operation);
267     FAIL_TEST (NULL != common_operation);
268     GNUNET_TESTBED_operation_done (common_operation);
269     common_operation = NULL;
270     result = PEERS_CONNECTED;
271     LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
272     delayed_connect_task =
273         GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3),
274                                       &do_delayed_connect, NULL);
275     break;
276   case PEERS_CONNECTED:
277     FAIL_TEST (NULL == peer1.operation);
278     FAIL_TEST (NULL == peer2.operation);
279     FAIL_TEST (NULL != common_operation);
280     GNUNET_TESTBED_operation_done (common_operation);
281     common_operation = NULL;
282     result = PEERS_CONNECTED_2;
283     LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
284     peer1.operation = GNUNET_TESTBED_peer_stop (peer1.peer, NULL, NULL);
285     peer2.operation = GNUNET_TESTBED_peer_stop (peer2.peer, NULL, NULL);
286     break;
287   default:
288     FAIL_TEST (0);
289   }
290 }
291
292
293 /**
294  * Signature of the event handler function called by the
295  * respective event controller.
296  *
297  * @param cls closure
298  * @param event information about the event
299  */
300 static void
301 controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
302 {
303   switch (event->type)
304   {
305   case GNUNET_TESTBED_ET_OPERATION_FINISHED:   /* Will be reached when we destroy peers */
306     FAIL_TEST (PEERS_STOPPED == result);
307     FAIL_TEST (NULL == event->details.operation_finished.op_cls);
308     FAIL_TEST (NULL == event->details.operation_finished.emsg);
309     FAIL_TEST (NULL == event->details.operation_finished.generic);
310     if (event->details.operation_finished.operation == peer1.operation)
311     {
312       GNUNET_TESTBED_operation_done (peer1.operation);
313       peer1.operation = NULL;
314       peer1.peer = NULL;
315     }
316     else if (event->details.operation_finished.operation == peer2.operation)
317     {
318       GNUNET_TESTBED_operation_done (peer2.operation);
319       peer2.operation = NULL;
320       peer2.peer = NULL;
321     }
322     else
323       FAIL_TEST (0);
324     if ((NULL == peer1.peer) && (NULL == peer2.peer))
325     {
326       result = SUCCESS;
327       GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
328     }
329     break;
330   case GNUNET_TESTBED_ET_PEER_START:
331     FAIL_TEST (INIT == result);
332     FAIL_TEST (event->details.peer_start.host == host);
333     if (event->details.peer_start.peer == peer1.peer)
334     {
335       peer1.is_running = GNUNET_YES;
336       GNUNET_TESTBED_operation_done (peer1.operation);
337       peer1.operation = NULL;
338     }
339     else if (event->details.peer_start.peer == peer2.peer)
340     {
341       peer2.is_running = GNUNET_YES;
342       GNUNET_TESTBED_operation_done (peer2.operation);
343       peer2.operation = NULL;
344     }
345     else
346       FAIL_TEST (0);
347     if ((GNUNET_YES == peer1.is_running) && (GNUNET_YES == peer2.is_running))
348     {
349       result = PEERS_STARTED;
350       common_operation =
351           GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
352                                           peer2.peer);
353     }
354     break;
355   case GNUNET_TESTBED_ET_PEER_STOP:
356     FAIL_TEST (PEERS_CONNECTED_2 == result);
357     if (event->details.peer_stop.peer == peer1.peer)
358     {
359       peer1.is_running = GNUNET_NO;
360       GNUNET_TESTBED_operation_done (peer1.operation);
361       peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
362     }
363     else if (event->details.peer_stop.peer == peer2.peer)
364     {
365       peer2.is_running = GNUNET_NO;
366       GNUNET_TESTBED_operation_done (peer2.operation);
367       peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
368     }
369     else
370       FAIL_TEST (0);
371     if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running))
372       result = PEERS_STOPPED;
373     break;
374   case GNUNET_TESTBED_ET_CONNECT:
375     switch (result)
376     {
377     case PEERS_STARTED:
378     case PEERS_CONNECTED:
379       FAIL_TEST (NULL == peer1.operation);
380       FAIL_TEST (NULL == peer2.operation);
381       FAIL_TEST (NULL != common_operation);
382       FAIL_TEST ((event->details.peer_connect.peer1 == peer1.peer) &&
383                      (event->details.peer_connect.peer2 == peer2.peer));
384       break;
385     default:
386       FAIL_TEST (0);
387     }
388     break;
389   default:
390     FAIL_TEST (0);
391   };
392 }
393
394
395 /**
396  * Functions of this signature are called when a peer has been successfully
397  * created
398  *
399  * @param cls the closure from GNUNET_TESTBED_peer_create()
400  * @param peer the handle for the created peer; NULL on any error during
401  *          creation
402  * @param emsg NULL if peer is not NULL; else MAY contain the error description
403  */
404 static void
405 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
406 {
407   struct PeerContext *pc = cls;
408
409   FAIL_TEST (NULL != pc->operation);
410   FAIL_TEST (NULL != peer);
411   FAIL_TEST (NULL == pc->peer);
412   pc->peer = peer;
413   GNUNET_TESTBED_operation_done (pc->operation);
414   pc->operation = GNUNET_TESTBED_peer_start (NULL, pc->peer, NULL, NULL);
415 }
416
417
418 /**
419  * Callback which will be called to after a host registration succeeded or failed
420  *
421  * @param cls the host which has been registered
422  * @param emsg the error message; NULL if host registration is successful
423  */
424 static void
425 registration_comp (void *cls, const char *emsg)
426 {
427   FAIL_TEST (cls == neighbour);
428   reg_handle = NULL;
429   peer1.operation =
430       GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
431                                   &peer1);
432   peer2.operation =
433       GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
434                                   &peer2);
435   FAIL_TEST (NULL != peer1.operation);
436   FAIL_TEST (NULL != peer2.operation);
437 }
438
439
440 /**
441  * Callback to signal successfull startup of the controller process
442  *
443  * @param cls the closure from GNUNET_TESTBED_controller_start()
444  * @param cfg the configuration with which the controller has been started;
445  *          NULL if status is not GNUNET_OK
446  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
447  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
448  */
449 static void
450 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, int status)
451 {
452   uint64_t event_mask;
453
454   FAIL_TEST (GNUNET_OK == status);
455   event_mask = 0;
456   event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
457   event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
458   event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
459   event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
460   controller =
461       GNUNET_TESTBED_controller_connect (cfg, host, event_mask, &controller_cb,
462                                          NULL);
463   FAIL_TEST (NULL != controller);
464   neighbour = GNUNET_TESTBED_host_create ("localhost", NULL, 0);
465   FAIL_TEST (NULL != neighbour);
466   reg_handle =
467       GNUNET_TESTBED_register_host (controller, neighbour, &registration_comp,
468                                     neighbour);
469   FAIL_TEST (NULL != reg_handle);
470 }
471
472
473
474 /**
475  * Main run function.
476  *
477  * @param cls NULL
478  * @param args arguments passed to GNUNET_PROGRAM_run
479  * @param cfgfile the path to configuration file
480  * @param cfg the configuration file handle
481  */
482 static void
483 run (void *cls, char *const *args, const char *cfgfile,
484      const struct GNUNET_CONFIGURATION_Handle *config)
485 {
486   host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
487   FAIL_TEST (NULL != host);
488   cfg = GNUNET_CONFIGURATION_dup (config);
489   cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
490                                         NULL);
491   abort_task =
492       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
493                                     (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
494                                     NULL);
495 }
496
497
498 /**
499  * Main function
500  */
501 int
502 main (int argc, char **argv)
503 {
504   int ret;
505
506   char *const argv2[] = { "test_testbed_api_2peers_1controller",
507     "-c", "test_testbed_api.conf",
508     NULL
509   };
510   struct GNUNET_GETOPT_CommandLineOption options[] = {
511     GNUNET_GETOPT_OPTION_END
512   };
513   result = INIT;
514   ret =
515       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
516                           "test_testbed_api_2peers_1controller", "nohelp",
517                           options, &run, NULL);
518   if ((GNUNET_OK != ret) || (SUCCESS != result))
519     return 1;
520   return 0;
521 }
522
523 /* end of test_testbed_api_2peers_1controller.c */