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