fix
[oweals/gnunet.git] / src / testbed / test_testbed_api_operations.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_operations.c
21  * @brief tests cases for testbed_api_operations.c
22  * @author Sree Harsha Totakura
23  */
24
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "testbed_api_operations.h"
28
29 /**
30  * Generic logging shortcut
31  */
32 #define LOG(kind,...)                           \
33   GNUNET_log (kind, __VA_ARGS__)
34
35 /**
36  * Delay to start step task
37  */
38 #define STEP_DELAY                                                      \
39   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
40
41 /**
42  * Queue A. Initially the max active is set to 2 and then reduced to 0 - this
43  * should block op2 even after op1 has finished. Later the max active is set to
44  * 2 and this should start op2
45  */
46 struct OperationQueue *q1;
47
48 /**
49  * Queue B. Max active set to 2 is not changed throughout the test
50  */
51 struct OperationQueue *q2;
52
53 /**
54  * This operation should go into both queues and block op2 until it is done
55  */
56 struct GNUNET_TESTBED_Operation *op1;
57
58 /**
59  * This operation should go into q1 and q2
60  */
61 struct GNUNET_TESTBED_Operation *op2;
62
63 /**
64  * This operation should go into both queues and should consume 2 units of
65  * resources on both queues. Since op2 needs a resource from both queues and is
66  * queues before this operation, it will be blocked until op2 is released even
67  * though q1 has enough free resources
68  */
69 struct GNUNET_TESTBED_Operation *op3;
70
71 /**
72  * Just like op3, this operation also consumes 2 units of resources on both
73  * queues. Since this is queued after op3 and both queues are at max active
74  * 2. This will be blocked until op3 is done.
75  */
76 struct GNUNET_TESTBED_Operation *op4;
77
78 /**
79  * This operation is started after op4 is released and should consume only 1
80  * resource on queue q1. It should be started along with op6 and op7
81  */
82 struct GNUNET_TESTBED_Operation *op5;
83
84 /**
85  * This operation is started after op4 is released and should consume only 1
86  * resource on q2. It should be started along with op5 and op7
87  */
88 struct GNUNET_TESTBED_Operation *op6;
89
90 /**
91  * This operation is started after op4 is released and should consume 1 resource
92  * on both queues q1 and q1. It should be started along with op5 and op6.  It is
93  * then inactivated when op6 is released.  op8's start should release this
94  * operation implicitly.
95  */
96 struct GNUNET_TESTBED_Operation *op7;
97
98 /**
99  * This operation is started after op6 is finished in step task.  It consumes 2
100  * resources on both queues q1 and q2.  This operation should evict op7.  After
101  * starting, it should be made inactive, active and inactive again in the step task.
102  */
103 struct GNUNET_TESTBED_Operation *op8;
104
105 /**
106  * This opration is started after activating op8.  It should consume a resource
107  * on queues q1 and q2.  It should not be started until op8 is again made
108  * inactive at which point it should be released.  It can be released as soon as
109  * it begins.
110  */
111 struct GNUNET_TESTBED_Operation *op9;
112
113 /**
114  * The delay task identifier
115  */
116 struct GNUNET_SCHEDULER_Task * step_task;
117
118
119 /**
120  * Enumeration of test stages
121  */
122 enum Test
123 {
124     /**
125      * Initial stage
126      */
127   TEST_INIT,
128
129     /**
130      * op1 has been started
131      */
132   TEST_OP1_STARTED,
133
134     /**
135      * op1 has been released
136      */
137   TEST_OP1_RELEASED,
138
139   /**
140    * Temporary pause where no operations should start as we set max active in q1
141    * to 0 in stage TEST_OP1_STARTED
142    */
143   TEST_PAUSE,
144
145     /**
146      * op2 has started
147      */
148   TEST_OP2_STARTED,
149
150     /**
151      * op2 released
152      */
153   TEST_OP2_RELEASED,
154
155   /**
156    * op3 has started
157    */
158   TEST_OP3_STARTED,
159
160   /**
161    * op3 has finished
162    */
163   TEST_OP3_RELEASED,
164
165   /**
166    * op4 has started
167    */
168   TEST_OP4_STARTED,
169
170   /**
171    * op4 has released
172    */
173   TEST_OP4_RELEASED,
174
175   /**
176    * op5, op6, op7 started
177    */
178   TEST_OP5_6_7_STARTED,
179
180   /**
181    * op5 has released
182    */
183   TEST_OP5_RELEASED,
184
185   /**
186    * op6 has released
187    */
188   TEST_OP6_RELEASED,
189
190   /**
191    * op8 has began waiting
192    */
193   TEST_OP8_WAITING,
194
195   /**
196    * op7 has released
197    */
198   TEST_OP7_RELEASED,
199
200   /**
201    * op8 has started
202    */
203   TEST_OP8_STARTED,
204
205   /**
206    * op8 is inactive
207    */
208   TEST_OP8_INACTIVE_1,
209
210   /**
211    * op8 is active
212    */
213   TEST_OP8_ACTIVE,
214
215   /**
216    * op8 has been released
217    */
218   TEST_OP8_RELEASED,
219
220   /**
221    * op9 has started
222    */
223   TEST_OP9_STARTED,
224
225   /**
226    * op9 has been released
227    */
228   TEST_OP9_RELEASED
229 };
230
231 /**
232  * The test result
233  */
234 enum Test result;
235
236
237 /**
238  * Function to call to start an operation once all
239  * queues the operation is part of declare that the
240  * operation can be activated.
241  */
242 static void
243 start_cb (void *cls);
244
245
246 /**
247  * Function to cancel an operation (release all associated resources).  This can
248  * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
249  * operation generated an event) or AFTER the operation generated an event due
250  * to a call to "GNUNET_TESTBED_operation_done".  Thus it is not guaranteed that
251  * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
252  * Implementations of this function are expected to clean up whatever state is
253  * in 'cls' and release all resources associated with the operation.
254  */
255 static void
256 release_cb (void *cls);
257
258
259 /**
260  * Task to simulate artificial delay and change the test stage
261  *
262  * @param cls NULL
263  */
264 static void
265 step (void *cls)
266 {
267   GNUNET_assert (NULL != step_task);
268   step_task = NULL;
269   switch (result)
270   {
271   case TEST_OP1_STARTED:
272     GNUNET_TESTBED_operation_release_ (op1);
273     GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0);
274     op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb);
275     GNUNET_TESTBED_operation_queue_insert2_ (q1, op3, 2);
276     GNUNET_TESTBED_operation_queue_insert2_ (q2, op3, 2);
277     GNUNET_TESTBED_operation_begin_wait_ (op3);
278     op4 = GNUNET_TESTBED_operation_create_ (&op4, &start_cb, &release_cb);
279     GNUNET_TESTBED_operation_queue_insert2_ (q1, op4, 2);
280     GNUNET_TESTBED_operation_queue_insert2_ (q2, op4, 2);
281     GNUNET_TESTBED_operation_begin_wait_ (op4);
282     break;
283   case TEST_OP1_RELEASED:
284     result = TEST_PAUSE;
285     GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 2);
286     break;
287   case TEST_OP2_STARTED:
288     GNUNET_TESTBED_operation_release_ (op2);
289     break;
290   case TEST_OP3_STARTED:
291     GNUNET_TESTBED_operation_release_ (op3);
292     break;
293   case TEST_OP4_STARTED:
294     GNUNET_TESTBED_operation_release_ (op4);
295     break;
296   case TEST_OP6_RELEASED:
297     op8 = GNUNET_TESTBED_operation_create_ (&op8, &start_cb, &release_cb);
298     GNUNET_TESTBED_operation_queue_insert2_ (q1, op8, 2);
299     GNUNET_TESTBED_operation_queue_insert2_ (q2, op8, 2);
300     result = TEST_OP8_WAITING;
301     GNUNET_TESTBED_operation_begin_wait_ (op8);
302     break;
303   case TEST_OP8_STARTED:
304     GNUNET_TESTBED_operation_inactivate_ (op8);
305     result = TEST_OP8_INACTIVE_1;
306     step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
307     break;
308   case TEST_OP8_INACTIVE_1:
309     GNUNET_TESTBED_operation_activate_ (op8);
310     result = TEST_OP8_ACTIVE;
311     op9 = GNUNET_TESTBED_operation_create_ (&op9, &start_cb, &release_cb);
312     GNUNET_TESTBED_operation_queue_insert2_ (q1, op9, 1);
313     GNUNET_TESTBED_operation_queue_insert2_ (q2, op9, 1);
314     GNUNET_TESTBED_operation_begin_wait_ (op9);
315     step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
316     break;
317   case TEST_OP8_ACTIVE:
318     GNUNET_TESTBED_operation_inactivate_ (op8);
319     /* op8 should be released by now due to above call */
320     GNUNET_assert (TEST_OP8_RELEASED == result);
321     break;
322   case TEST_OP9_STARTED:
323     GNUNET_TESTBED_operation_release_ (op9);
324     break;
325   default:
326     GNUNET_assert (0);
327   }
328 }
329
330
331 /**
332  * Function to call to start an operation once all
333  * queues the operation is part of declare that the
334  * operation can be activated.
335  */
336 static void
337 start_cb (void *cls)
338 {
339   switch (result)
340   {
341   case TEST_INIT:
342     GNUNET_assert (&op1 == cls);
343     result = TEST_OP1_STARTED;
344     GNUNET_assert (NULL == step_task);
345     step_task =
346         GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
347     break;
348   case TEST_PAUSE:
349     GNUNET_assert (&op2 == cls);
350     result = TEST_OP2_STARTED;
351     GNUNET_assert (NULL == step_task);
352     step_task =
353         GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
354     break;
355   case TEST_OP2_RELEASED:
356     GNUNET_assert (&op3 == cls);
357     result = TEST_OP3_STARTED;
358     GNUNET_assert (NULL == step_task);
359     step_task =
360         GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
361     break;
362   case TEST_OP3_RELEASED:
363     GNUNET_assert (&op4 == cls);
364     result = TEST_OP4_STARTED;
365     GNUNET_assert (NULL == step_task);
366     step_task =
367         GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
368     break;
369   case TEST_OP4_RELEASED:
370   {
371     static int nops;
372
373     nops++;
374     if (nops == 3)
375     {
376       result = TEST_OP5_6_7_STARTED;
377       GNUNET_TESTBED_operation_release_ (op5);
378       op5 = NULL;
379     }
380   }
381     break;
382   case TEST_OP7_RELEASED:
383     GNUNET_assert (&op8 == cls);
384     result = TEST_OP8_STARTED;
385     step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
386     break;
387   case TEST_OP8_RELEASED:
388     GNUNET_assert (&op9 == cls);
389     result = TEST_OP9_STARTED;
390     step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
391     break;
392   default:
393     GNUNET_assert (0);
394   }
395 }
396
397
398 /**
399  * Function to cancel an operation (release all associated resources).  This can
400  * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
401  * operation generated an event) or AFTER the operation generated an event due
402  * to a call to "GNUNET_TESTBED_operation_done".  Thus it is not guaranteed that
403  * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
404  * Implementations of this function are expected to clean up whatever state is
405  * in 'cls' and release all resources associated with the operation.
406  */
407 static void
408 release_cb (void *cls)
409 {
410   switch (result)
411   {
412   case TEST_OP1_STARTED:
413     GNUNET_assert (&op1 == cls);
414     result = TEST_OP1_RELEASED;
415     op1 = NULL;
416     step_task =
417         GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
418     break;
419   case TEST_OP2_STARTED:
420     GNUNET_assert (&op2 == cls);
421     result = TEST_OP2_RELEASED;
422     GNUNET_assert (NULL == step_task);
423     break;
424   case TEST_OP3_STARTED:
425     GNUNET_assert (&op3 == cls);
426     result = TEST_OP3_RELEASED;
427     GNUNET_assert (NULL == step_task);
428     break;
429   case TEST_OP4_STARTED:
430     GNUNET_assert (&op4 == cls);
431     result = TEST_OP4_RELEASED;
432     GNUNET_assert (NULL == step_task);
433     op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb);
434     GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1);
435     GNUNET_TESTBED_operation_begin_wait_ (op5);
436     op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb);
437     GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1);
438     GNUNET_TESTBED_operation_begin_wait_ (op6);
439     op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb);
440     GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1);
441     GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1);
442     GNUNET_TESTBED_operation_begin_wait_ (op7);
443     break;
444   case TEST_OP5_6_7_STARTED:
445     result = TEST_OP5_RELEASED;
446     op5 = NULL;
447     GNUNET_TESTBED_operation_release_ (op6);
448     break;
449   case TEST_OP5_RELEASED:
450     op6 = NULL;
451     result = TEST_OP6_RELEASED;
452     GNUNET_TESTBED_operation_inactivate_ (op7);
453     step_task = GNUNET_SCHEDULER_add_now (&step, NULL);
454     break;
455   case TEST_OP8_WAITING:
456     GNUNET_assert (&op7 == cls);
457     op7 = NULL;
458     result = TEST_OP7_RELEASED;
459     break;
460   case TEST_OP8_ACTIVE:
461     result = TEST_OP8_RELEASED;
462     op8 = NULL;
463     break;
464   case TEST_OP9_STARTED:
465     GNUNET_assert (&op9 == cls);
466     result = TEST_OP9_RELEASED;
467     GNUNET_TESTBED_operation_queue_destroy_ (q1);
468     GNUNET_TESTBED_operation_queue_destroy_ (q2);
469     q1 = NULL;
470     q2 = NULL;
471     break;
472   default:
473     GNUNET_assert (0);
474   }
475 }
476
477
478 /**
479  * Main run function.
480  *
481  * @param cls NULL
482  * @param args arguments passed to GNUNET_PROGRAM_run
483  * @param cfgfile the path to configuration file
484  * @param cfg the configuration file handle
485  */
486 static void
487 run (void *cls, char *const *args, const char *cfgfile,
488      const struct GNUNET_CONFIGURATION_Handle *config)
489 {
490   q1 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 1);
491   GNUNET_assert (NULL != q1);
492   q2 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 2);
493   GNUNET_assert (NULL != q2);
494   op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb);
495   GNUNET_assert (NULL != op1);
496   op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb);
497   GNUNET_TESTBED_operation_queue_insert_ (q1, op1);
498   GNUNET_TESTBED_operation_queue_insert_ (q2, op1);
499   GNUNET_TESTBED_operation_begin_wait_ (op1);
500   GNUNET_TESTBED_operation_queue_insert_ (q1, op2);
501   GNUNET_TESTBED_operation_queue_insert_ (q2, op2);
502   GNUNET_TESTBED_operation_begin_wait_ (op2);
503   result = TEST_INIT;
504 }
505
506
507 /**
508  * Main function
509  */
510 int
511 main (int argc, char **argv)
512 {
513   int ret;
514   char *const argv2[] =
515       { "test_testbed_api_operations", "-c", "test_testbed_api.conf", NULL };
516   struct GNUNET_GETOPT_CommandLineOption options[] =
517       { GNUNET_GETOPT_OPTION_END };
518
519   ret =
520       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
521                           "test_testbed_api_operations", "nohelp", options,
522                           &run, NULL);
523   if ((GNUNET_OK != ret) || (TEST_OP9_RELEASED != result))
524     return 1;
525   op1 = NULL;
526   op2 = NULL;
527   op3 = NULL;
528   op4 = NULL;
529   op5 = NULL;
530   op6 = NULL;
531   op7 = NULL;
532   op8 = NULL;
533   op9 = NULL;
534   q1 = NULL;
535   q2 = NULL;
536   return 0;
537 }
538
539 /* end of test_testbed_api_operations.c */