- support caching through inactive operations
[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 enough free resources
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.  It is
89  * then inactivated when op6 is released.  op8's start should release this
90  * operation implicitly.
91  */
92 struct GNUNET_TESTBED_Operation *op7;
93
94 /**
95  * This operation is started after op6 is finished in step task.  It consumes 2
96  * resources on both queues q1 and q1.
97  */
98 struct GNUNET_TESTBED_Operation *op8;
99
100 /**
101  * The delay task identifier
102  */
103 GNUNET_SCHEDULER_TaskIdentifier step_task;
104
105
106 /**
107  * Enumeration of test stages
108  */
109 enum Test
110 {
111     /**
112      * Initial stage
113      */
114   TEST_INIT,
115
116     /**
117      * op1 has been started
118      */
119   TEST_OP1_STARTED,
120
121     /**
122      * op1 has been released
123      */
124   TEST_OP1_RELEASED,
125
126   /**
127    * Temporary pause where no operations should start as we set max active in q1
128    * to 0 in stage TEST_OP1_STARTED
129    */
130   TEST_PAUSE,
131
132     /**
133      * op2 has started
134      */
135   TEST_OP2_STARTED,
136
137     /**
138      * op2 released
139      */
140   TEST_OP2_RELEASED,
141
142   /**
143    * op3 has started
144    */
145   TEST_OP3_STARTED,
146
147   /**
148    * op3 has finished
149    */
150   TEST_OP3_RELEASED,
151
152   /**
153    * op4 has started
154    */
155   TEST_OP4_STARTED,
156
157   /**
158    * op4 has released
159    */
160   TEST_OP4_RELEASED,
161
162   /**
163    * op5, op6, op7 started
164    */
165   TEST_OP5_6_7_STARTED,
166
167   /**
168    * op5 has released
169    */
170   TEST_OP5_RELEASED,
171
172   /**
173    * op6 has released
174    */
175   TEST_OP6_RELEASED,
176
177   /**
178    * op8 has began waiting
179    */
180   TEST_OP8_WAITING,
181
182   /**
183    * op7 has released
184    */
185   TEST_OP7_RELEASED,
186
187   /**
188    * op8 has started
189    */
190   TEST_OP8_STARTED,
191
192   /**
193    * op8 has been released
194    */
195   TEST_OP8_RELEASED
196 };
197
198 /**
199  * The test result
200  */
201 enum Test result;
202
203
204 /**
205  * Function to call to start an operation once all
206  * queues the operation is part of declare that the
207  * operation can be activated.
208  */
209 static void
210 start_cb (void *cls);
211
212
213 /**
214  * Function to cancel an operation (release all associated resources).  This can
215  * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
216  * operation generated an event) or AFTER the operation generated an event due
217  * to a call to "GNUNET_TESTBED_operation_done".  Thus it is not guaranteed that
218  * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
219  * Implementations of this function are expected to clean up whatever state is
220  * in 'cls' and release all resources associated with the operation.
221  */
222 static void
223 release_cb (void *cls);
224
225
226 /**
227  * Task to simulate artificial delay and change the test stage
228  *
229  * @param cls NULL
230  * @param tc the task context
231  */
232 static void
233 step (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
234 {
235   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != step_task);
236   step_task = GNUNET_SCHEDULER_NO_TASK;
237   switch (result)
238   {
239   case TEST_OP1_STARTED:
240     GNUNET_TESTBED_operation_release_ (op1);
241     GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0);
242     op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb);
243     GNUNET_TESTBED_operation_queue_insert2_ (q1, op3, 2);
244     GNUNET_TESTBED_operation_queue_insert2_ (q2, op3, 2);
245     GNUNET_TESTBED_operation_begin_wait_ (op3);
246     op4 = GNUNET_TESTBED_operation_create_ (&op4, &start_cb, &release_cb);
247     GNUNET_TESTBED_operation_queue_insert2_ (q1, op4, 2);
248     GNUNET_TESTBED_operation_queue_insert2_ (q2, op4, 2);
249     GNUNET_TESTBED_operation_begin_wait_ (op4);
250     break;
251   case TEST_OP1_RELEASED:
252     result = TEST_PAUSE;
253     GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 2);
254     break;
255   case TEST_OP2_STARTED:
256     GNUNET_TESTBED_operation_release_ (op2);
257     break;
258   case TEST_OP3_STARTED:
259     GNUNET_TESTBED_operation_release_ (op3);
260     break;
261   case TEST_OP4_STARTED:
262     GNUNET_TESTBED_operation_release_ (op4);
263     break;
264   case TEST_OP6_RELEASED:    
265     op8 = GNUNET_TESTBED_operation_create_ (&op8, &start_cb, &release_cb);    
266     GNUNET_TESTBED_operation_queue_insert2_ (q1, op8, 2);
267     GNUNET_TESTBED_operation_queue_insert2_ (q2, op8, 2);
268     result = TEST_OP8_WAITING;
269     GNUNET_TESTBED_operation_begin_wait_ (op8);
270     break;
271   case TEST_OP8_STARTED:
272     GNUNET_TESTBED_operation_release_ (op8);
273     break;
274   default:
275     GNUNET_assert (0);
276   }
277 }
278
279
280 /**
281  * Function to call to start an operation once all
282  * queues the operation is part of declare that the
283  * operation can be activated.
284  */
285 static void
286 start_cb (void *cls)
287 {
288   switch (result)
289   {
290   case TEST_INIT:
291     GNUNET_assert (&op1 == cls);
292     result = TEST_OP1_STARTED;
293     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
294     step_task =
295         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
296     break;
297   case TEST_PAUSE:
298     GNUNET_assert (&op2 == cls);
299     result = TEST_OP2_STARTED;
300     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
301     step_task =
302         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
303     break;
304   case TEST_OP2_RELEASED:
305     GNUNET_assert (&op3 == cls);
306     result = TEST_OP3_STARTED;
307     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
308     step_task =
309         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
310     break;
311   case TEST_OP3_RELEASED:
312     GNUNET_assert (&op4 == cls);
313     result = TEST_OP4_STARTED;
314     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
315     step_task =
316         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
317     break;
318   case TEST_OP4_RELEASED:
319   {
320     static int nops;
321
322     nops++;
323     if (nops == 3)
324     {
325       result = TEST_OP5_6_7_STARTED;
326       GNUNET_TESTBED_operation_release_ (op5);
327       op5 = NULL;
328     }
329   }
330     break;
331   case TEST_OP7_RELEASED:
332     GNUNET_assert (&op8 == cls);
333     result = TEST_OP8_STARTED;
334     step_task = GNUNET_SCHEDULER_add_now (&step, NULL);
335     break;
336   default:
337     GNUNET_assert (0);
338   }
339 }
340
341
342 /**
343  * Function to cancel an operation (release all associated resources).  This can
344  * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
345  * operation generated an event) or AFTER the operation generated an event due
346  * to a call to "GNUNET_TESTBED_operation_done".  Thus it is not guaranteed that
347  * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
348  * Implementations of this function are expected to clean up whatever state is
349  * in 'cls' and release all resources associated with the operation.
350  */
351 static void
352 release_cb (void *cls)
353 {
354   switch (result)
355   {
356   case TEST_OP1_STARTED:
357     GNUNET_assert (&op1 == cls);
358     result = TEST_OP1_RELEASED;
359     op1 = NULL;
360     step_task =
361         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
362     break;
363   case TEST_OP2_STARTED:
364     GNUNET_assert (&op2 == cls);
365     result = TEST_OP2_RELEASED;
366     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
367     //step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
368     break;
369   case TEST_OP3_STARTED:
370     GNUNET_assert (&op3 == cls);
371     result = TEST_OP3_RELEASED;
372     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
373     break;
374   case TEST_OP4_STARTED:
375     GNUNET_assert (&op4 == cls);
376     result = TEST_OP4_RELEASED;
377     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
378     op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb);
379     GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1);
380     GNUNET_TESTBED_operation_begin_wait_ (op5);
381     op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb);
382     GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1);
383     GNUNET_TESTBED_operation_begin_wait_ (op6);
384     op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb);
385     GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1);
386     GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1);
387     GNUNET_TESTBED_operation_begin_wait_ (op7);
388     break;
389   case TEST_OP5_6_7_STARTED:
390     result = TEST_OP5_RELEASED;
391     op5 = NULL;
392     GNUNET_TESTBED_operation_release_ (op6);
393     break;
394   case TEST_OP5_RELEASED:
395     op6 = NULL;
396     result = TEST_OP6_RELEASED;
397     GNUNET_TESTBED_operation_inactivate_ (op7);
398     step_task = GNUNET_SCHEDULER_add_now (&step, NULL);
399     break;
400   case TEST_OP8_WAITING:
401     GNUNET_assert (&op7 == cls);
402     op7 = NULL;
403     result = TEST_OP7_RELEASED;
404     break;
405   case TEST_OP8_STARTED:
406     result = TEST_OP8_RELEASED;
407     op8 = NULL;
408     GNUNET_TESTBED_operation_queue_destroy_ (q1);
409     GNUNET_TESTBED_operation_queue_destroy_ (q2);
410     q1 = NULL;
411     q2 = NULL;
412     break;
413   default:
414     GNUNET_assert (0);
415   }
416 }
417
418
419 /**
420  * Main run function.
421  *
422  * @param cls NULL
423  * @param args arguments passed to GNUNET_PROGRAM_run
424  * @param cfgfile the path to configuration file
425  * @param cfg the configuration file handle
426  */
427 static void
428 run (void *cls, char *const *args, const char *cfgfile,
429      const struct GNUNET_CONFIGURATION_Handle *config)
430 {
431   q1 = GNUNET_TESTBED_operation_queue_create_ (1);
432   GNUNET_assert (NULL != q1);
433   q2 = GNUNET_TESTBED_operation_queue_create_ (2);
434   GNUNET_assert (NULL != q2);
435   op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb);
436   GNUNET_assert (NULL != op1);
437   op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb);
438   GNUNET_TESTBED_operation_queue_insert_ (q1, op1);
439   GNUNET_TESTBED_operation_queue_insert_ (q2, op1);
440   GNUNET_TESTBED_operation_begin_wait_ (op1);
441   GNUNET_TESTBED_operation_queue_insert_ (q1, op2);
442   GNUNET_TESTBED_operation_queue_insert_ (q2, op2);
443   GNUNET_TESTBED_operation_begin_wait_ (op2);
444   result = TEST_INIT;
445 }
446
447
448 /**
449  * Main function
450  */
451 int
452 main (int argc, char **argv)
453 {
454   int ret;
455   char *const argv2[] =
456       { "test_testbed_api_operations", "-c", "test_testbed_api.conf", NULL };
457   struct GNUNET_GETOPT_CommandLineOption options[] =
458       { GNUNET_GETOPT_OPTION_END };
459
460   ret =
461       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
462                           "test_testbed_api_operations", "nohelp", options,
463                           &run, NULL);
464   if ((GNUNET_OK != ret) || (TEST_OP8_RELEASED != result))
465     return 1;
466   op1 = NULL;
467   op2 = NULL;
468   op3 = NULL;
469   op4 = NULL;
470   op5 = NULL;
471   op6 = NULL;
472   op7 = NULL;
473   op8 = NULL;
474   q1 = NULL;
475   q2 = NULL;
476   return 0;
477 }
478
479 /* end of test_testbed_api_operations.c */