48ce2546ea1474bdee582fa141c6747b8fc1a76f
[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 destroy on slave 1 successful
92      */
93     SLAVE1_PEER_DESTROY_SUCCESS,
94
95     /**
96      * Peer destory on slave 2 successful; Marks test as successful
97      */
98     SUCCESS
99   };
100
101 /**
102  * Host for running master controller
103  */
104 static struct GNUNET_TESTBED_Host *host;
105
106 /**
107  * The master controller process
108  */
109 static struct GNUNET_TESTBED_ControllerProc *cp;
110
111 /**
112  * Handle to master controller
113  */
114 static struct GNUNET_TESTBED_Controller *mc;
115
116 /**
117  * Slave host for running slave controller
118  */
119 static struct GNUNET_TESTBED_Host *slave;
120
121 /**
122  * Another slave host for running another slave controller
123  */
124 static struct GNUNET_TESTBED_Host *slave2;
125
126 /**
127  * Slave host registration handle
128  */
129 static struct GNUNET_TESTBED_HostRegistrationHandle *rh;
130
131 /**
132  * Handle to global configuration
133  */
134 static struct GNUNET_CONFIGURATION_Handle *cfg;
135
136 /**
137  * Abort task
138  */
139 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
140
141 /**
142  * Operation handle for linking controllers
143  */
144 static struct GNUNET_TESTBED_Operation *op;
145
146 /**
147  * Handle to peer started at slave 1
148  */
149 static struct GNUNET_TESTBED_Peer *slave1_peer;
150
151 /**
152  * Handle to peer started at slave 2
153  */
154 static struct GNUNET_TESTBED_Peer *slave2_peer;
155
156 /**
157  * Event mask
158  */
159 uint64_t event_mask;
160
161 /**
162  * Global testing status
163  */
164 static enum Stage result;
165
166
167 /**
168  * Shutdown nicely
169  *
170  * @param cls NULL
171  * @param tc the task context
172  */
173 static void
174 do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
175 {
176   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
177     GNUNET_SCHEDULER_cancel (abort_task);
178   if (NULL != slave2)
179     GNUNET_TESTBED_host_destroy (slave2);
180     if (NULL != slave)
181     GNUNET_TESTBED_host_destroy (slave);
182   if (NULL != host)
183     GNUNET_TESTBED_host_destroy (host);
184   if (NULL != mc)
185     GNUNET_TESTBED_controller_disconnect (mc);
186   if (NULL != cfg)
187     GNUNET_CONFIGURATION_destroy (cfg);
188   if (NULL != cp)
189     GNUNET_TESTBED_controller_stop (cp);
190   if (NULL != rh)
191     GNUNET_TESTBED_cancel_registration (rh);
192   
193 }
194
195
196 /**
197  * abort task to run on test timed out
198  *
199  * @param cls NULL
200  * @param tc the task context
201  */
202 static void
203 do_abort (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
204 {
205   LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
206   abort_task = GNUNET_SCHEDULER_NO_TASK;
207   do_shutdown (cls, tc);
208 }
209
210
211 /**
212  * Functions of this signature are called when a peer has been successfully
213  * created
214  *
215  * @param cls the closure from GNUNET_TESTBED_peer_create()
216  * @param peer the handle for the created peer; NULL on any error during
217  *          creation
218  * @param emsg NULL if peer is not NULL; else MAY contain the error description
219  */
220 static void 
221 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
222 {
223   switch (result)
224   {
225   case SLAVE2_LINK_SUCCESS:
226     GNUNET_assert (NULL != peer);
227     GNUNET_assert (NULL == emsg);
228     result = SLAVE1_PEER_CREATE_SUCCESS;    
229     slave1_peer = peer;
230     GNUNET_TESTBED_operation_done (op);    
231     op = GNUNET_TESTBED_peer_create (mc, slave2, cfg, peer_create_cb, NULL);
232     GNUNET_assert (NULL != op);
233     break;
234   case SLAVE1_PEER_CREATE_SUCCESS:
235     GNUNET_assert (NULL != peer);
236     GNUNET_assert (NULL == emsg);
237     result = SLAVE2_PEER_CREATE_SUCCESS;
238     slave2_peer = peer;    
239     GNUNET_TESTBED_operation_done (op);
240     op = GNUNET_TESTBED_peer_destroy (slave1_peer);
241     GNUNET_assert (NULL != op);    
242     break;
243   default:
244     GNUNET_assert (0);    
245   }
246 }
247
248
249 /**
250  * Checks the event if it is an operation finished event and if indicates a
251  * successfull completion of operation
252  *
253  * @param event the event information to check
254  */
255 static void
256 check_operation_success (const struct GNUNET_TESTBED_EventInformation *event)
257 {
258   GNUNET_assert (NULL != event);
259   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
260   GNUNET_assert (event->details.operation_finished.operation == op);
261   GNUNET_assert (NULL == event->details.operation_finished.op_cls);
262   GNUNET_assert (NULL == event->details.operation_finished.emsg);
263   GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC ==
264                  event->details.operation_finished.pit);
265   GNUNET_assert (NULL == event->details.operation_finished.op_result.generic);
266 }
267
268
269 /**
270  * Signature of the event handler function called by the
271  * respective event controller.
272  *
273  * @param cls closure
274  * @param event information about the event
275  */
276 static void 
277 controller_cb(void *cls, const struct GNUNET_TESTBED_EventInformation *event)
278 {
279   switch (result)
280   {
281   case SLAVE2_REGISTERED:
282     check_operation_success (event);    
283     GNUNET_TESTBED_operation_done (op);
284     op = NULL;
285     result = SLAVE1_LINK_SUCCESS;
286     GNUNET_assert (NULL != slave2);
287     GNUNET_assert (NULL != slave);
288     op = GNUNET_TESTBED_controller_link (mc, slave2, slave, cfg, GNUNET_YES);
289     GNUNET_assert (NULL != op);
290     break;
291   case SLAVE1_LINK_SUCCESS:
292     check_operation_success (event);
293     GNUNET_TESTBED_operation_done (op);
294     op = NULL;
295     result = SLAVE2_LINK_SUCCESS;
296     op = GNUNET_TESTBED_peer_create (mc, slave, cfg, peer_create_cb, NULL);
297     GNUNET_assert (NULL != op);
298     break;
299   case SLAVE2_PEER_CREATE_SUCCESS:
300     check_operation_success (event);
301     GNUNET_TESTBED_operation_done (op);
302     result = SLAVE1_PEER_DESTROY_SUCCESS;
303     op = GNUNET_TESTBED_peer_destroy (slave2_peer);
304     GNUNET_assert (NULL != slave2_peer);
305     break;
306   case SLAVE1_PEER_DESTROY_SUCCESS:
307     check_operation_success (event);
308     GNUNET_TESTBED_operation_done (op);
309     result = SUCCESS;
310     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
311     break;    
312   default:
313     GNUNET_assert (0);
314   }
315 }
316
317
318 /**
319  * Callback which will be called to after a host registration succeeded or failed
320  *
321  * @param cls the host which has been registered
322  * @param emsg the error message; NULL if host registration is successful
323  */
324 static void 
325 registration_cont (void *cls, const char *emsg)
326 {
327   rh = NULL;
328   switch (result)
329   {
330   case MASTER_STARTED:
331     GNUNET_assert (NULL == emsg);
332     GNUNET_assert (NULL != mc);
333     result = SLAVE1_REGISTERED;
334     slave2 = GNUNET_TESTBED_host_create_with_id (2, "127.0.0.1", NULL, 0);
335     GNUNET_assert (NULL != slave2);
336     rh = GNUNET_TESTBED_register_host (mc, slave2, &registration_cont, NULL);
337     GNUNET_assert (NULL != rh);
338     break;
339   case SLAVE1_REGISTERED:
340     GNUNET_assert (NULL == emsg);
341     GNUNET_assert (NULL != mc);
342     result = SLAVE2_REGISTERED;
343     GNUNET_assert (NULL != cfg);
344     op = GNUNET_TESTBED_controller_link (mc, slave, NULL, cfg, GNUNET_YES);
345     GNUNET_assert (NULL != op);
346     break;
347   default:
348     GNUNET_assert (0);
349   }
350 }
351
352 /**
353  * Callback to signal successfull startup of the controller process
354  *
355  * @param cls the closure from GNUNET_TESTBED_controller_start()
356  * @param cfg the configuration with which the controller has been started;
357  *          NULL if status is not GNUNET_OK
358  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
359  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
360  */
361 static void 
362 status_cb (void *cls, 
363            const struct GNUNET_CONFIGURATION_Handle *config, int status)
364 {
365   switch (result)
366   {
367   case INIT:
368     GNUNET_assert (GNUNET_OK == status);
369     event_mask = 0;
370     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
371     event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
372     event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
373     event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
374     mc = GNUNET_TESTBED_controller_connect (config, host, event_mask,
375                                             &controller_cb, NULL);
376     GNUNET_assert (NULL != mc);
377     result = MASTER_STARTED;
378     slave = GNUNET_TESTBED_host_create_with_id (1, "127.0.0.1", NULL, 0);
379     GNUNET_assert (NULL != slave);
380     rh = GNUNET_TESTBED_register_host (mc, slave, &registration_cont, NULL);
381     GNUNET_assert (NULL != rh);
382     break;
383   default:
384     GNUNET_assert (0);
385   }
386 }
387
388
389 /**
390  * Main run function. 
391  *
392  * @param cls NULL
393  * @param args arguments passed to GNUNET_PROGRAM_run
394  * @param cfgfile the path to configuration file
395  * @param cfg the configuration file handle
396  */
397 static void
398 run (void *cls, char *const *args, const char *cfgfile,
399      const struct GNUNET_CONFIGURATION_Handle *config)
400 {
401   host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
402   GNUNET_assert (NULL != host);
403   cfg = GNUNET_CONFIGURATION_dup (config);
404   cp =
405     GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb, NULL);
406   abort_task = GNUNET_SCHEDULER_add_delayed 
407     (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), 
408      &do_abort, NULL);
409 }
410
411
412 /**
413  * Main function
414  */
415 int main (int argc, char **argv)
416 {
417   int ret;
418   char *const argv2[] = { "test_testbed_api_controllerlink",
419                           "-c", "test_testbed_api.conf",
420                           NULL
421   };
422   struct GNUNET_GETOPT_CommandLineOption options[] = {
423     GNUNET_GETOPT_OPTION_END
424   };
425   char *const remote_args[] = {
426     "ssh", "-o", "BatchMode=yes", "127.0.0.1", "echo", "Hello", "World", NULL
427   };
428   struct GNUNET_OS_Process *auxp;
429   enum GNUNET_OS_ProcessStatusType type;
430   unsigned long code;
431   
432   auxp = GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL,
433                                       NULL, NULL, "ssh", remote_args);
434   GNUNET_assert (NULL != auxp);
435   do
436   {
437     ret = GNUNET_OS_process_status (auxp, &type, &code);    
438     GNUNET_assert (GNUNET_SYSERR != ret);
439     (void) usleep (300);    
440   } while (GNUNET_NO == ret);
441   if (0 != code)
442   {    
443     (void) printf ("Unable to run the test as this system is not configured "
444                    "to use password less SSH logins to localhost.\n"
445                    "Marking test as successful\n");
446     return 0;    
447   }  
448   result = INIT;
449   ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
450                             "test_testbed_api_controllerlink", "nohelp", options, &run,
451                             NULL);
452   if ((GNUNET_OK != ret) || (SUCCESS != result))
453     return 1;
454   return 0;
455 }