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