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