b10e454de11c5997c6b47c15ed94b33be7ce02cf
[oweals/gnunet.git] / src / testbed / test_testbed_api_controllerlink.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_controllerlink.c
23  * @brief testcase for testing controller to subcontroller linking
24  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testing_lib-new.h"
30 #include "gnunet_testbed_service.h"
31
32 /**
33  * Generic logging shortcut
34  */
35 #define LOG(kind,...)                           \
36   GNUNET_log (kind, __VA_ARGS__)
37
38 /**
39  * Debug logging shorthand
40  */
41 #define LOG_DEBUG(...)                          \
42   LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
43
44 /**
45  * Different stages in testing
46  */
47 enum Stage
48 {
49
50     /**
51      * Initial stage
52      */
53   INIT,
54
55     /**
56      * Master controller has started
57      */
58   MASTER_STARTED,
59
60     /**
61      * The first slave has been registered at master controller
62      */
63   SLAVE1_REGISTERED,
64
65     /**
66      * The second slave has been registered at the master controller
67      */
68   SLAVE2_REGISTERED,
69
70     /**
71      * Link from master to slave 1 has been successfully created
72      */
73   SLAVE1_LINK_SUCCESS,
74
75     /**
76      * Link from slave 1 to slave 2 has been successfully created.
77      */
78   SLAVE2_LINK_SUCCESS,
79
80     /**
81      * Peer create on slave 1 successful
82      */
83   SLAVE1_PEER_CREATE_SUCCESS,
84
85     /**
86      * Peer create on slave 2 successful
87      */
88   SLAVE2_PEER_CREATE_SUCCESS,
89
90     /**
91      * Peer startup on slave 1 successful
92      */
93   SLAVE1_PEER_START_SUCCESS,
94
95     /**
96      * Peer on slave 1 successfully stopped
97      */
98   SLAVE1_PEER_STOP_SUCCESS,
99
100     /**
101      * Peer startup on slave 2 successful
102      */
103   SLAVE2_PEER_START_SUCCESS,
104
105     /**
106      * Peer on slave 2 successfully stopped
107      */
108   SLAVE2_PEER_STOP_SUCCESS,
109
110     /**
111      * Peer destroy on slave 1 successful
112      */
113   SLAVE1_PEER_DESTROY_SUCCESS,
114
115     /**
116      * Peer destory on slave 2 successful; Marks test as successful
117      */
118   SUCCESS
119 };
120
121 /**
122  * Host for running master controller
123  */
124 static struct GNUNET_TESTBED_Host *host;
125
126 /**
127  * The master controller process
128  */
129 static struct GNUNET_TESTBED_ControllerProc *cp;
130
131 /**
132  * Handle to master controller
133  */
134 static struct GNUNET_TESTBED_Controller *mc;
135
136 /**
137  * Slave host for running slave controller
138  */
139 static struct GNUNET_TESTBED_Host *slave;
140
141 /**
142  * Another slave host for running another slave controller
143  */
144 static struct GNUNET_TESTBED_Host *slave2;
145
146 /**
147  * Slave host registration handle
148  */
149 static struct GNUNET_TESTBED_HostRegistrationHandle *rh;
150
151 /**
152  * Handle to global configuration
153  */
154 static struct GNUNET_CONFIGURATION_Handle *cfg;
155
156 /**
157  * Abort task
158  */
159 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
160
161 /**
162  * Operation handle for linking controllers
163  */
164 static struct GNUNET_TESTBED_Operation *op;
165
166 /**
167  * Handle to peer started at slave 1
168  */
169 static struct GNUNET_TESTBED_Peer *slave1_peer;
170
171 /**
172  * Handle to peer started at slave 2
173  */
174 static struct GNUNET_TESTBED_Peer *slave2_peer;
175
176 /**
177  * Event mask
178  */
179 uint64_t event_mask;
180
181 /**
182  * Global testing status
183  */
184 static enum Stage result;
185
186
187 /**
188  * Shutdown nicely
189  *
190  * @param cls NULL
191  * @param tc the task context
192  */
193 static void
194 do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
195 {
196   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
197     GNUNET_SCHEDULER_cancel (abort_task);
198   if (NULL != slave2)
199     GNUNET_TESTBED_host_destroy (slave2);
200   if (NULL != slave)
201     GNUNET_TESTBED_host_destroy (slave);
202   if (NULL != host)
203     GNUNET_TESTBED_host_destroy (host);
204   if (NULL != mc)
205     GNUNET_TESTBED_controller_disconnect (mc);
206   if (NULL != cfg)
207     GNUNET_CONFIGURATION_destroy (cfg);
208   if (NULL != cp)
209     GNUNET_TESTBED_controller_stop (cp);
210   if (NULL != rh)
211     GNUNET_TESTBED_cancel_registration (rh);
212
213 }
214
215
216 /**
217  * abort task to run on test timed out
218  *
219  * @param cls NULL
220  * @param tc the task context
221  */
222 static void
223 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
224 {
225   LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
226   abort_task = GNUNET_SCHEDULER_NO_TASK;
227   do_shutdown (cls, tc);
228 }
229
230
231 /**
232  * Task for inserting delay between tests
233  *
234  * @param
235  * @return
236  */
237 static void
238 delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
239 {
240   switch (result)
241   {
242   case SLAVE1_PEER_START_SUCCESS:
243     op = GNUNET_TESTBED_peer_stop (slave1_peer);
244     GNUNET_assert (NULL != op);
245     break;
246   case SLAVE2_PEER_START_SUCCESS:
247     op = GNUNET_TESTBED_peer_stop (slave2_peer);
248     GNUNET_assert (NULL != op);
249     break;
250   default:
251     GNUNET_assert (0);
252   }
253 }
254
255
256 /**
257  * Functions of this signature are called when a peer has been successfully
258  * created
259  *
260  * @param cls the closure from GNUNET_TESTBED_peer_create()
261  * @param peer the handle for the created peer; NULL on any error during
262  *          creation
263  * @param emsg NULL if peer is not NULL; else MAY contain the error description
264  */
265 static void
266 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
267 {
268   switch (result)
269   {
270   case SLAVE2_LINK_SUCCESS:
271     GNUNET_assert (NULL != peer);
272     GNUNET_assert (NULL == emsg);
273     result = SLAVE1_PEER_CREATE_SUCCESS;
274     slave1_peer = peer;
275     GNUNET_TESTBED_operation_done (op);
276     op = GNUNET_TESTBED_peer_create (mc, slave2, cfg, peer_create_cb, NULL);
277     GNUNET_assert (NULL != op);
278     break;
279   case SLAVE1_PEER_CREATE_SUCCESS:
280     GNUNET_assert (NULL != peer);
281     GNUNET_assert (NULL == emsg);
282     result = SLAVE2_PEER_CREATE_SUCCESS;
283     slave2_peer = peer;
284     GNUNET_TESTBED_operation_done (op);
285     op = GNUNET_TESTBED_peer_start (slave1_peer);
286     GNUNET_assert (NULL != op);
287     break;
288   default:
289     GNUNET_assert (0);
290   }
291 }
292
293
294 /**
295  * Checks the event if it is an operation finished event and if indicates a
296  * successfull completion of operation
297  *
298  * @param event the event information to check
299  */
300 static void
301 check_operation_success (const struct GNUNET_TESTBED_EventInformation *event)
302 {
303   GNUNET_assert (NULL != event);
304   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
305   GNUNET_assert (event->details.operation_finished.operation == op);
306   GNUNET_assert (NULL == event->details.operation_finished.op_cls);
307   GNUNET_assert (NULL == event->details.operation_finished.emsg);
308   GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC ==
309                  event->details.operation_finished.pit);
310   GNUNET_assert (NULL == event->details.operation_finished.op_result.generic);
311 }
312
313
314 /**
315  * Signature of the event handler function called by the
316  * respective event controller.
317  *
318  * @param cls closure
319  * @param event information about the event
320  */
321 static void
322 controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
323 {
324   switch (result)
325   {
326   case SLAVE2_REGISTERED:
327     check_operation_success (event);
328     GNUNET_TESTBED_operation_done (op);
329     op = NULL;
330     result = SLAVE1_LINK_SUCCESS;
331     GNUNET_assert (NULL != slave2);
332     GNUNET_assert (NULL != slave);
333     op = GNUNET_TESTBED_controller_link (mc, slave2, slave, cfg, GNUNET_YES);
334     GNUNET_assert (NULL != op);
335     break;
336   case SLAVE1_LINK_SUCCESS:
337     check_operation_success (event);
338     GNUNET_TESTBED_operation_done (op);
339     op = NULL;
340     result = SLAVE2_LINK_SUCCESS;
341     op = GNUNET_TESTBED_peer_create (mc, slave, cfg, peer_create_cb, NULL);
342     GNUNET_assert (NULL != op);
343     break;
344   case SLAVE2_PEER_CREATE_SUCCESS:
345     GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
346     GNUNET_assert (event->details.peer_start.host == slave);
347     GNUNET_assert (event->details.peer_start.peer == slave1_peer);
348     GNUNET_TESTBED_operation_done (op);
349     result = SLAVE1_PEER_START_SUCCESS;
350     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
351                                   (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
352                                   NULL);
353     break;
354   case SLAVE1_PEER_START_SUCCESS:
355     GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
356     GNUNET_assert (event->details.peer_stop.peer == slave1_peer);
357     GNUNET_TESTBED_operation_done (op);
358     result = SLAVE1_PEER_STOP_SUCCESS;
359     op = GNUNET_TESTBED_peer_start (slave2_peer);
360     GNUNET_assert (NULL != op);
361     break;
362   case SLAVE1_PEER_STOP_SUCCESS:
363     GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
364     GNUNET_assert (event->details.peer_start.host == slave2);
365     GNUNET_assert (event->details.peer_start.peer == slave2_peer);
366     GNUNET_TESTBED_operation_done (op);
367     result = SLAVE2_PEER_START_SUCCESS;
368     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
369                                   (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
370                                   NULL);
371     break;
372   case SLAVE2_PEER_START_SUCCESS:
373     GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
374     GNUNET_assert (event->details.peer_stop.peer == slave2_peer);
375     GNUNET_TESTBED_operation_done (op);
376     result = SLAVE2_PEER_STOP_SUCCESS;
377     op = GNUNET_TESTBED_peer_destroy (slave1_peer);
378     GNUNET_assert (NULL != op);
379     break;
380   case SLAVE2_PEER_STOP_SUCCESS:
381     check_operation_success (event);
382     GNUNET_TESTBED_operation_done (op);
383     result = SLAVE1_PEER_DESTROY_SUCCESS;
384     op = GNUNET_TESTBED_peer_destroy (slave2_peer);
385     GNUNET_assert (NULL != op);
386     break;
387   case SLAVE1_PEER_DESTROY_SUCCESS:
388     check_operation_success (event);
389     GNUNET_TESTBED_operation_done (op);
390     result = SUCCESS;
391     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
392     break;
393   default:
394     GNUNET_assert (0);
395   }
396 }
397
398
399 /**
400  * Callback which will be called to after a host registration succeeded or failed
401  *
402  * @param cls the host which has been registered
403  * @param emsg the error message; NULL if host registration is successful
404  */
405 static void
406 registration_cont (void *cls, const char *emsg)
407 {
408   rh = NULL;
409   switch (result)
410   {
411   case MASTER_STARTED:
412     GNUNET_assert (NULL == emsg);
413     GNUNET_assert (NULL != mc);
414     result = SLAVE1_REGISTERED;
415     slave2 = GNUNET_TESTBED_host_create_with_id (2, "127.0.0.1", NULL, 0);
416     GNUNET_assert (NULL != slave2);
417     rh = GNUNET_TESTBED_register_host (mc, slave2, &registration_cont, NULL);
418     GNUNET_assert (NULL != rh);
419     break;
420   case SLAVE1_REGISTERED:
421     GNUNET_assert (NULL == emsg);
422     GNUNET_assert (NULL != mc);
423     result = SLAVE2_REGISTERED;
424     GNUNET_assert (NULL != cfg);
425     op = GNUNET_TESTBED_controller_link (mc, slave, NULL, cfg, GNUNET_YES);
426     GNUNET_assert (NULL != op);
427     break;
428   default:
429     GNUNET_assert (0);
430   }
431 }
432
433 /**
434  * Callback to signal successfull startup of the controller process
435  *
436  * @param cls the closure from GNUNET_TESTBED_controller_start()
437  * @param cfg the configuration with which the controller has been started;
438  *          NULL if status is not GNUNET_OK
439  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
440  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
441  */
442 static void
443 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config,
444            int status)
445 {
446   switch (result)
447   {
448   case INIT:
449     GNUNET_assert (GNUNET_OK == status);
450     event_mask = 0;
451     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
452     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
453     event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
454     event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
455     mc = GNUNET_TESTBED_controller_connect (config, host, event_mask,
456                                             &controller_cb, NULL);
457     GNUNET_assert (NULL != mc);
458     result = MASTER_STARTED;
459     slave = GNUNET_TESTBED_host_create_with_id (1, "127.0.0.1", NULL, 0);
460     GNUNET_assert (NULL != slave);
461     rh = GNUNET_TESTBED_register_host (mc, slave, &registration_cont, NULL);
462     GNUNET_assert (NULL != rh);
463     break;
464   default:
465     GNUNET_assert (0);
466   }
467 }
468
469
470 /**
471  * Main run function.
472  *
473  * @param cls NULL
474  * @param args arguments passed to GNUNET_PROGRAM_run
475  * @param cfgfile the path to configuration file
476  * @param cfg the configuration file handle
477  */
478 static void
479 run (void *cls, char *const *args, const char *cfgfile,
480      const struct GNUNET_CONFIGURATION_Handle *config)
481 {
482   host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
483   GNUNET_assert (NULL != host);
484   cfg = GNUNET_CONFIGURATION_dup (config);
485   cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
486                                         NULL);
487   abort_task =
488       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
489                                     (GNUNET_TIME_UNIT_MINUTES, 5), &do_abort,
490                                     NULL);
491 }
492
493
494 /**
495  * Main function
496  */
497 int
498 main (int argc, char **argv)
499 {
500   int ret;
501
502   char *const argv2[] = { "test_testbed_api_controllerlink",
503     "-c", "test_testbed_api.conf",
504     NULL
505   };
506   struct GNUNET_GETOPT_CommandLineOption options[] = {
507     GNUNET_GETOPT_OPTION_END
508   };
509   char *const remote_args[] = {
510     "ssh", "-o", "BatchMode=yes", "127.0.0.1", "echo", "Hello", "World", NULL
511   };
512   struct GNUNET_OS_Process *auxp;
513   enum GNUNET_OS_ProcessStatusType type;
514   unsigned long code;
515
516   auxp =
517       GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
518                                    NULL, "ssh", remote_args);
519   GNUNET_assert (NULL != auxp);
520   do
521   {
522     ret = GNUNET_OS_process_status (auxp, &type, &code);
523     GNUNET_assert (GNUNET_SYSERR != ret);
524     (void) usleep (300);
525   }
526   while (GNUNET_NO == ret);
527   GNUNET_OS_process_destroy (auxp);
528   if (0 != code)
529   {
530     (void) printf ("Unable to run the test as this system is not configured "
531                    "to use password less SSH logins to localhost.\n"
532                    "Marking test as successful\n");
533     return 0;
534   }
535   result = INIT;
536   ret =
537       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
538                           "test_testbed_api_controllerlink", "nohelp", options,
539                           &run, NULL);
540   if ((GNUNET_OK != ret) || (SUCCESS != result))
541     return 1;
542   return 0;
543 }