2320c4d1bf708795b5b0a5662b949af9aab24452
[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 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
262     break;
263   case TEST_PAUSE:
264     GNUNET_assert (&op2 == cls);
265     result = TEST_OP2_STARTED;
266     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
267     step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
268     break;
269   case TEST_OP2_RELEASED:
270     GNUNET_assert (&op3 == cls);
271     result = TEST_OP3_STARTED;
272     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
273     step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
274     break;
275   case TEST_OP3_RELEASED:
276     GNUNET_assert (&op4 == cls);
277     result = TEST_OP4_STARTED;
278     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
279     step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step,
280                                               NULL);
281     break;
282   case TEST_OP4_RELEASED:
283     {
284       static int nops;
285       
286       nops++;
287       if (nops == 3)
288       {
289         result = TEST_OP5_6_7_STARTED;
290         GNUNET_TESTBED_operation_release_ (op5);
291         op5 = NULL;
292       }
293     }
294     break;
295   default:
296     GNUNET_assert (0);
297   }
298 }
299
300
301 /**
302  * Function to cancel an operation (release all associated resources).  This can
303  * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
304  * operation generated an event) or AFTER the operation generated an event due
305  * to a call to "GNUNET_TESTBED_operation_done".  Thus it is not guaranteed that
306  * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
307  * Implementations of this function are expected to clean up whatever state is
308  * in 'cls' and release all resources associated with the operation.
309  */
310 static void
311 release_cb (void *cls)
312 {
313   switch (result)
314   {
315   case TEST_OP1_STARTED:
316     GNUNET_assert (&op1 == cls);
317     result = TEST_OP1_RELEASED;
318     op1 = NULL;
319     step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step,
320                                               NULL);
321     break;
322   case TEST_OP2_STARTED:
323     GNUNET_assert (&op2 == cls);
324     result = TEST_OP2_RELEASED;
325     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
326     //step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
327     break;
328   case TEST_OP3_STARTED:
329     GNUNET_assert (&op3 == cls);
330     result = TEST_OP3_RELEASED;
331     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
332     break;
333   case TEST_OP4_STARTED:
334     GNUNET_assert (&op4 == cls);
335     result = TEST_OP4_RELEASED;
336     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
337     op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb);
338     GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1);
339     GNUNET_TESTBED_operation_begin_wait_ (op5);
340     op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb);
341     GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1);
342     GNUNET_TESTBED_operation_begin_wait_ (op6);
343     op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb);
344     GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1);
345     GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1);
346     GNUNET_TESTBED_operation_begin_wait_ (op7);
347     break;
348   case TEST_OP5_6_7_STARTED:
349     result = TEST_OP5_RELEASED;
350     op5 = NULL;
351     GNUNET_TESTBED_operation_release_ (op6);
352     break;
353   case TEST_OP5_RELEASED:
354     op6 = NULL;
355     result = TEST_OP6_RELEASED;
356     GNUNET_TESTBED_operation_release_ (op7);
357     break;
358   case TEST_OP6_RELEASED:
359     result = TEST_OP7_RELEASED;
360     op7 = NULL;
361     GNUNET_TESTBED_operation_queue_destroy_ (q1);
362     GNUNET_TESTBED_operation_queue_destroy_ (q2);
363     q1 = NULL;
364     q2 = NULL;
365     break;
366   default:
367     GNUNET_assert (0);
368   }
369 }
370
371
372 /**
373  * Main run function.
374  *
375  * @param cls NULL
376  * @param args arguments passed to GNUNET_PROGRAM_run
377  * @param cfgfile the path to configuration file
378  * @param cfg the configuration file handle
379  */
380 static void
381 run (void *cls, char *const *args, const char *cfgfile,
382      const struct GNUNET_CONFIGURATION_Handle *config)
383 {
384   q1 = GNUNET_TESTBED_operation_queue_create_ (1);
385   GNUNET_assert (NULL != q1);
386   q2 = GNUNET_TESTBED_operation_queue_create_ (2);
387   GNUNET_assert (NULL != q2);
388   op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb);
389   GNUNET_assert (NULL != op1);
390   op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb);
391   GNUNET_TESTBED_operation_queue_insert_ (q1, op1);
392   GNUNET_TESTBED_operation_queue_insert_ (q2, op1);
393   GNUNET_TESTBED_operation_begin_wait_ (op1);
394   GNUNET_TESTBED_operation_queue_insert_ (q1, op2);
395   GNUNET_TESTBED_operation_queue_insert_ (q2, op2);
396   GNUNET_TESTBED_operation_begin_wait_ (op2);
397   result = TEST_INIT;
398 }
399
400
401 /**
402  * Main function
403  */
404 int
405 main (int argc, char **argv)
406 {
407   int ret;
408   char *const argv2[] =
409       { "test_testbed_api_operations", "-c", "test_testbed_api.conf", NULL };
410   struct GNUNET_GETOPT_CommandLineOption options[] =
411       { GNUNET_GETOPT_OPTION_END };
412
413   ret =
414       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
415                           "test_testbed_api_operations", "nohelp", options,
416                           &run, NULL);
417   if ((GNUNET_OK != ret) || (TEST_OP7_RELEASED != result))
418     return 1;
419   op1 = NULL;
420   op2 = NULL;
421   op3 = NULL;
422   q1 = NULL;
423   q2 = NULL;
424   return 0;
425 }
426
427 /* end of test_testbed_api_operations.c */