-tests
[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, NULL, NULL);
244     GNUNET_assert (NULL != op);
245     break;
246   case SLAVE2_PEER_START_SUCCESS:
247     op = GNUNET_TESTBED_peer_stop (slave2_peer, NULL, NULL);
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, NULL, NULL);
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 (NULL == event->details.operation_finished.generic);
309 }
310
311
312 /**
313  * Signature of the event handler function called by the
314  * respective event controller.
315  *
316  * @param cls closure
317  * @param event information about the event
318  */
319 static void
320 controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
321 {
322   switch (result)
323   {
324   case SLAVE2_REGISTERED:
325     check_operation_success (event);
326     GNUNET_TESTBED_operation_done (op);
327     op = NULL;
328     result = SLAVE1_LINK_SUCCESS;
329     GNUNET_assert (NULL != slave2);
330     GNUNET_assert (NULL != slave);
331     op = GNUNET_TESTBED_controller_link (mc, slave2, slave, cfg, GNUNET_YES);
332     GNUNET_assert (NULL != op);
333     break;
334   case SLAVE1_LINK_SUCCESS:
335     check_operation_success (event);
336     GNUNET_TESTBED_operation_done (op);
337     op = NULL;
338     result = SLAVE2_LINK_SUCCESS;
339     op = GNUNET_TESTBED_peer_create (mc, slave, cfg, peer_create_cb, NULL);
340     GNUNET_assert (NULL != op);
341     break;
342   case SLAVE2_PEER_CREATE_SUCCESS:
343     GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
344     GNUNET_assert (event->details.peer_start.host == slave);
345     GNUNET_assert (event->details.peer_start.peer == slave1_peer);
346     GNUNET_TESTBED_operation_done (op);
347     result = SLAVE1_PEER_START_SUCCESS;
348     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
349                                   (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
350                                   NULL);
351     break;
352   case SLAVE1_PEER_START_SUCCESS:
353     GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
354     GNUNET_assert (event->details.peer_stop.peer == slave1_peer);
355     GNUNET_TESTBED_operation_done (op);
356     result = SLAVE1_PEER_STOP_SUCCESS;
357     op = GNUNET_TESTBED_peer_start (slave2_peer, NULL, NULL);
358     GNUNET_assert (NULL != op);
359     break;
360   case SLAVE1_PEER_STOP_SUCCESS:
361     GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
362     GNUNET_assert (event->details.peer_start.host == slave2);
363     GNUNET_assert (event->details.peer_start.peer == slave2_peer);
364     GNUNET_TESTBED_operation_done (op);
365     result = SLAVE2_PEER_START_SUCCESS;
366     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
367                                   (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
368                                   NULL);
369     break;
370   case SLAVE2_PEER_START_SUCCESS:
371     GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
372     GNUNET_assert (event->details.peer_stop.peer == slave2_peer);
373     GNUNET_TESTBED_operation_done (op);
374     result = SLAVE2_PEER_STOP_SUCCESS;
375     op = GNUNET_TESTBED_peer_destroy (slave1_peer);
376     GNUNET_assert (NULL != op);
377     break;
378   case SLAVE2_PEER_STOP_SUCCESS:
379     check_operation_success (event);
380     GNUNET_TESTBED_operation_done (op);
381     result = SLAVE1_PEER_DESTROY_SUCCESS;
382     op = GNUNET_TESTBED_peer_destroy (slave2_peer);
383     GNUNET_assert (NULL != op);
384     break;
385   case SLAVE1_PEER_DESTROY_SUCCESS:
386     check_operation_success (event);
387     GNUNET_TESTBED_operation_done (op);
388     result = SUCCESS;
389     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
390     break;
391   default:
392     GNUNET_assert (0);
393   }
394 }
395
396
397 /**
398  * Callback which will be called to after a host registration succeeded or failed
399  *
400  * @param cls the host which has been registered
401  * @param emsg the error message; NULL if host registration is successful
402  */
403 static void
404 registration_cont (void *cls, const char *emsg)
405 {
406   rh = NULL;
407   switch (result)
408   {
409   case MASTER_STARTED:
410     GNUNET_assert (NULL == emsg);
411     GNUNET_assert (NULL != mc);
412     result = SLAVE1_REGISTERED;
413     slave2 = GNUNET_TESTBED_host_create_with_id (2, "127.0.0.1", NULL, 0);
414     GNUNET_assert (NULL != slave2);
415     rh = GNUNET_TESTBED_register_host (mc, slave2, &registration_cont, NULL);
416     GNUNET_assert (NULL != rh);
417     break;
418   case SLAVE1_REGISTERED:
419     GNUNET_assert (NULL == emsg);
420     GNUNET_assert (NULL != mc);
421     result = SLAVE2_REGISTERED;
422     GNUNET_assert (NULL != cfg);
423     op = GNUNET_TESTBED_controller_link (mc, slave, NULL, cfg, GNUNET_YES);
424     GNUNET_assert (NULL != op);
425     break;
426   default:
427     GNUNET_assert (0);
428   }
429 }
430
431 /**
432  * Callback to signal successfull startup of the controller process
433  *
434  * @param cls the closure from GNUNET_TESTBED_controller_start()
435  * @param cfg the configuration with which the controller has been started;
436  *          NULL if status is not GNUNET_OK
437  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
438  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
439  */
440 static void
441 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config,
442            int status)
443 {
444   switch (result)
445   {
446   case INIT:
447     GNUNET_assert (GNUNET_OK == status);
448     event_mask = 0;
449     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
450     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
451     event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
452     event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
453     mc = GNUNET_TESTBED_controller_connect (config, host, event_mask,
454                                             &controller_cb, NULL);
455     GNUNET_assert (NULL != mc);
456     result = MASTER_STARTED;
457     slave = GNUNET_TESTBED_host_create_with_id (1, "127.0.0.1", NULL, 0);
458     GNUNET_assert (NULL != slave);
459     rh = GNUNET_TESTBED_register_host (mc, slave, &registration_cont, NULL);
460     GNUNET_assert (NULL != rh);
461     break;
462   default:
463     GNUNET_assert (0);
464   }
465 }
466
467
468 /**
469  * Main run function.
470  *
471  * @param cls NULL
472  * @param args arguments passed to GNUNET_PROGRAM_run
473  * @param cfgfile the path to configuration file
474  * @param cfg the configuration file handle
475  */
476 static void
477 run (void *cls, char *const *args, const char *cfgfile,
478      const struct GNUNET_CONFIGURATION_Handle *config)
479 {
480   host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
481   GNUNET_assert (NULL != host);
482   cfg = GNUNET_CONFIGURATION_dup (config);
483   cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
484                                         NULL);
485   abort_task =
486       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
487                                     (GNUNET_TIME_UNIT_MINUTES, 5), &do_abort,
488                                     NULL);
489 }
490
491
492 /**
493  * Main function
494  */
495 int
496 main (int argc, char **argv)
497 {
498   int ret;
499
500   char *const argv2[] = { "test_testbed_api_controllerlink",
501     "-c", "test_testbed_api.conf",
502     NULL
503   };
504   struct GNUNET_GETOPT_CommandLineOption options[] = {
505     GNUNET_GETOPT_OPTION_END
506   };
507   char *const remote_args[] = {
508     "ssh", "-o", "BatchMode=yes", "127.0.0.1", "echo", "Hello", "World", NULL
509   };
510   struct GNUNET_OS_Process *auxp;
511   enum GNUNET_OS_ProcessStatusType type;
512   unsigned long code;
513
514   auxp =
515       GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
516                                    NULL, "ssh", remote_args);
517   GNUNET_assert (NULL != auxp);
518   do
519   {
520     ret = GNUNET_OS_process_status (auxp, &type, &code);
521     GNUNET_assert (GNUNET_SYSERR != ret);
522     (void) usleep (300);
523   }
524   while (GNUNET_NO == ret);
525   GNUNET_OS_process_destroy (auxp);
526   if (0 != code)
527   {
528     (void) printf ("Unable to run the test as this system is not configured "
529                    "to use password less SSH logins to localhost.\n"
530                    "Marking test as successful\n");
531     return 0;
532   }
533   result = INIT;
534   ret =
535       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
536                           "test_testbed_api_controllerlink", "nohelp", options,
537                           &run, NULL);
538   if ((GNUNET_OK != ret) || (SUCCESS != result))
539     return 1;
540   return 0;
541 }
542
543 /* end of test_testbed_api_controllerlink.c */
544