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