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