-fix doxygen issues
[oweals/gnunet.git] / src / datastore / test_datastore_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2004, 2005, 2006, 2007, 2009 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  * @file datastore/test_datastore_api.c
22  * @brief Test for the basic datastore API.
23  * @author Christian Grothoff
24  *
25  * TODO:
26  * - test reservation failure
27  */
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_datastore_service.h"
33 #include "gnunet_testing_lib.h"
34
35
36 /**
37  * How long until we give up on transmitting the message?
38  */
39 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
40
41 #define ITERATIONS 256
42
43 static struct GNUNET_DATASTORE_Handle *datastore;
44
45 static struct GNUNET_TIME_Absolute now;
46
47 static int ok;
48
49 /**
50  * Name of plugin under test.
51  */
52 static const char *plugin_name;
53
54 static size_t
55 get_size (int i)
56 {
57   return 8 * i;
58 }
59
60
61 static const void *
62 get_data (int i)
63 {
64   static char buf[60000];
65
66   memset (buf, i, 8 * i);
67   return buf;
68 }
69
70
71 static int
72 get_type (int i)
73 {
74   return i + 1;
75 }
76
77
78 static int
79 get_priority (int i)
80 {
81   return i + 1;
82 }
83
84
85 static int
86 get_anonymity (int i)
87 {
88   return i;
89 }
90
91
92 static struct GNUNET_TIME_Absolute
93 get_expiration (int i)
94 {
95   struct GNUNET_TIME_Absolute av;
96
97   av.abs_value_us = now.abs_value_us + 20000000000LL - i * 1000 * 1000LL;
98   return av;
99 }
100
101 enum RunPhase
102 {
103   RP_DONE = 0,
104   RP_PUT = 1,
105   RP_GET = 2,
106   RP_DEL = 3,
107   RP_DO_DEL = 4,
108   RP_DELVALIDATE = 5,
109   RP_RESERVE = 6,
110   RP_PUT_MULTIPLE = 7,
111   RP_PUT_MULTIPLE_NEXT = 8,
112   RP_GET_MULTIPLE = 9,
113   RP_GET_MULTIPLE_NEXT = 10,
114   RP_UPDATE = 11,
115   RP_UPDATE_VALIDATE = 12,
116   RP_ERROR
117 };
118
119
120 struct CpsRunContext
121 {
122   struct GNUNET_HashCode key;
123   int i;
124   int rid;
125   const struct GNUNET_CONFIGURATION_Handle *cfg;
126   void *data;
127   size_t size;
128   enum RunPhase phase;
129   uint64_t uid;
130   uint64_t offset;
131   uint64_t first_uid;
132 };
133
134
135 static void
136 run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
137
138
139 static void
140 check_success (void *cls,
141                int success,
142                struct GNUNET_TIME_Absolute min_expiration,
143                const char *msg)
144 {
145   struct CpsRunContext *crc = cls;
146
147   if (GNUNET_OK != success)
148   {
149     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
150                 "Operation %d/%d not successfull: `%s'\n", crc->phase, crc->i,
151                 msg);
152     crc->phase = RP_ERROR;
153   }
154   GNUNET_free_non_null (crc->data);
155   crc->data = NULL;
156   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
157                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
158 }
159
160
161 static void
162 get_reserved (void *cls,
163               int success,
164               struct GNUNET_TIME_Absolute min_expiration,
165               const char *msg)
166 {
167   struct CpsRunContext *crc = cls;
168
169   if (0 >= success)
170     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171                 "Error obtaining reservation: `%s'\n",
172                 msg);
173   GNUNET_assert (0 < success);
174   crc->rid = success;
175   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
176                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
177 }
178
179
180 static void
181 check_value (void *cls,
182              const struct GNUNET_HashCode *key,
183              size_t size,
184              const void *data,
185              enum GNUNET_BLOCK_Type type,
186              uint32_t priority,
187              uint32_t anonymity,
188              struct GNUNET_TIME_Absolute expiration,
189              uint64_t uid)
190 {
191   struct CpsRunContext *crc = cls;
192   int i;
193
194   i = crc->i;
195   if (NULL == key)
196   {
197     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198                 "Value check failed (got NULL key) in %d/%d\n",
199                 crc->phase,
200                 crc->i);
201     crc->phase = RP_ERROR;
202     GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
203                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
204     return;
205   }
206 #if 0
207   FPRINTF (stderr,
208            "Check value got `%s' of size %u, type %d, expire %s\n",
209            GNUNET_h2s (key), (unsigned int) size, type,
210            GNUNET_STRINGS_absolute_time_to_string (expiration));
211   FPRINTF (stderr,
212            "Check value iteration %d wants size %u, type %d, expire %s\n", i,
213            (unsigned int) get_size (i), get_type (i),
214            GNUNET_STRINGS_absolute_time_to_string (get_expiration(i)));
215 #endif
216   GNUNET_assert (size == get_size (i));
217   GNUNET_assert (0 == memcmp (data, get_data (i), size));
218   GNUNET_assert (type == get_type (i));
219   GNUNET_assert (priority == get_priority (i));
220   GNUNET_assert (anonymity == get_anonymity (i));
221   GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
222   crc->offset++;
223   if (crc->i == 0)
224   {
225     crc->phase = RP_DEL;
226     crc->i = ITERATIONS;
227   }
228   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
229                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
230 }
231
232
233 static void
234 delete_value (void *cls,
235               const struct GNUNET_HashCode *key,
236               size_t size,
237               const void *data,
238               enum GNUNET_BLOCK_Type type,
239               uint32_t priority,
240               uint32_t anonymity,
241               struct GNUNET_TIME_Absolute expiration,
242               uint64_t uid)
243 {
244   struct CpsRunContext *crc = cls;
245
246   GNUNET_assert (NULL == crc->data);
247   GNUNET_assert (NULL != key);
248   crc->size = size;
249   crc->key = *key;
250   crc->data = GNUNET_malloc (size);
251   memcpy (crc->data, data, size);
252   crc->phase = RP_DO_DEL;
253   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
254                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
255 }
256
257
258 static void
259 check_nothing (void *cls, const struct GNUNET_HashCode * key, size_t size,
260                const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
261                uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
262                uint64_t uid)
263 {
264   struct CpsRunContext *crc = cls;
265
266   GNUNET_assert (key == NULL);
267   if (crc->i == 0)
268     crc->phase = RP_RESERVE;
269   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
270                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
271 }
272
273
274 static void
275 check_multiple (void *cls,
276                 const struct GNUNET_HashCode *key,
277                 size_t size,
278                 const void *data,
279                 enum GNUNET_BLOCK_Type type,
280                 uint32_t priority,
281                 uint32_t anonymity,
282                 struct GNUNET_TIME_Absolute expiration,
283                 uint64_t uid)
284 {
285   struct CpsRunContext *crc = cls;
286
287   GNUNET_assert (key != NULL);
288   switch (crc->phase)
289   {
290   case RP_GET_MULTIPLE:
291     crc->phase = RP_GET_MULTIPLE_NEXT;
292     crc->first_uid = uid;
293     crc->offset++;
294     break;
295   case RP_GET_MULTIPLE_NEXT:
296     GNUNET_assert (uid != crc->first_uid);
297     crc->phase = RP_UPDATE;
298     break;
299   default:
300     GNUNET_break (0);
301     crc->phase = RP_ERROR;
302     break;
303   }
304   if (priority == get_priority (42))
305     crc->uid = uid;
306   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
307                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
308 }
309
310
311 static void
312 check_update (void *cls,
313               const struct GNUNET_HashCode *key,
314               size_t size,
315               const void *data,
316               enum GNUNET_BLOCK_Type type,
317               uint32_t priority,
318               uint32_t anonymity,
319               struct GNUNET_TIME_Absolute expiration,
320               uint64_t uid)
321 {
322   struct CpsRunContext *crc = cls;
323
324   GNUNET_assert (key != NULL);
325   if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
326       (priority == get_priority (42) + 100))
327     crc->phase = RP_DONE;
328   else
329   {
330     GNUNET_assert (size == get_size (43));
331     crc->offset++;
332   }
333   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
334                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
335 }
336
337
338 static void
339 run_continuation (void *cls,
340                   const struct GNUNET_SCHEDULER_TaskContext *tc)
341 {
342   struct CpsRunContext *crc = cls;
343
344   ok = (int) crc->phase;
345   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346               "Test in phase %u\n",
347               crc->phase);
348   switch (crc->phase)
349   {
350   case RP_PUT:
351     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352                 "Executing `%s' number %u\n",
353                 "PUT",
354                 crc->i);
355     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
356     GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
357                           get_data (crc->i), get_type (crc->i),
358                           get_priority (crc->i), get_anonymity (crc->i), 0,
359                           get_expiration (crc->i), 1, 1, TIMEOUT,
360                           &check_success, crc);
361     crc->i++;
362     if (crc->i == ITERATIONS)
363       crc->phase = RP_GET;
364     break;
365   case RP_GET:
366     crc->i--;
367     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368                 "Executing `%s' number %u\n",
369                 "GET",
370                 crc->i);
371     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
372     GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
373                               get_type (crc->i), 1, 1, TIMEOUT, &check_value,
374                               crc);
375     break;
376   case RP_DEL:
377     crc->i--;
378     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379                 "Executing `%s' number %u\n",
380                 "DEL",
381                 crc->i);
382     crc->data = NULL;
383     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
384     GNUNET_assert (NULL !=
385                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
386                                              get_type (crc->i), 1, 1, TIMEOUT,
387                                              &delete_value, crc));
388     break;
389   case RP_DO_DEL:
390     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391                 "Executing `%s' number %u\n",
392                 "DO_DEL",
393                 crc->i);
394     if (crc->i == 0)
395     {
396       crc->i = ITERATIONS;
397       crc->phase = RP_DELVALIDATE;
398     }
399     else
400     {
401       crc->phase = RP_DEL;
402     }
403     GNUNET_assert (NULL !=
404                    GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
405                                             crc->data, 1, 1, TIMEOUT,
406                                             &check_success, crc));
407     break;
408   case RP_DELVALIDATE:
409     crc->i--;
410     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411                 "Executing `%s' number %u\n",
412                 "DEL-VALIDATE", crc->i);
413     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
414     GNUNET_assert (NULL !=
415                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
416                                              get_type (crc->i), 1, 1, TIMEOUT,
417                                              &check_nothing, crc));
418     break;
419   case RP_RESERVE:
420     crc->phase = RP_PUT_MULTIPLE;
421     GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2, 1, 1, TIMEOUT,
422                               &get_reserved, crc);
423     break;
424   case RP_PUT_MULTIPLE:
425     crc->phase = RP_PUT_MULTIPLE_NEXT;
426     GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
427                           get_data (42), get_type (42), get_priority (42),
428                           get_anonymity (42), 0, get_expiration (42), 1, 1,
429                           TIMEOUT, &check_success, crc);
430     break;
431   case RP_PUT_MULTIPLE_NEXT:
432     crc->phase = RP_GET_MULTIPLE;
433     GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (43),
434                           get_data (43), get_type (42), get_priority (43),
435                           get_anonymity (43), 0, get_expiration (43), 1, 1,
436                           TIMEOUT, &check_success, crc);
437     break;
438   case RP_GET_MULTIPLE:
439     GNUNET_assert (NULL !=
440                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
441                                              get_type (42), 1, 1, TIMEOUT,
442                                              &check_multiple, crc));
443     break;
444   case RP_GET_MULTIPLE_NEXT:
445     GNUNET_assert (NULL !=
446                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
447                                              get_type (42), 1, 1, TIMEOUT,
448                                              &check_multiple, crc));
449     break;
450   case RP_UPDATE:
451     GNUNET_assert (crc->uid > 0);
452     crc->phase = RP_UPDATE_VALIDATE;
453     GNUNET_DATASTORE_update (datastore, crc->uid, 100, get_expiration (42), 1,
454                              1, TIMEOUT, &check_success, crc);
455     break;
456   case RP_UPDATE_VALIDATE:
457     GNUNET_assert (NULL !=
458                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
459                                              get_type (42), 1, 1, TIMEOUT,
460                                              &check_update, crc));
461     break;
462   case RP_DONE:
463     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n");
464     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
465     GNUNET_free (crc);
466     ok = 0;
467     break;
468   case RP_ERROR:
469     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
470     GNUNET_free (crc);
471     ok = 43;
472     break;
473   }
474 }
475
476
477 static void
478 run_tests (void *cls,
479            int32_t success,
480            struct GNUNET_TIME_Absolute min_expiration,
481            const char *msg)
482 {
483   struct CpsRunContext *crc = cls;
484
485   switch (success)
486   {
487   case GNUNET_YES:
488     GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
489                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
490     return;
491   case GNUNET_NO:
492     FPRINTF (stderr,
493              "%s", "Test 'put' operation failed, key already exists (!?)\n");
494     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
495     GNUNET_free (crc);
496     return;
497   case GNUNET_SYSERR:
498     FPRINTF (stderr,
499              "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
500              msg);
501     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
502     GNUNET_free (crc);
503     return;
504   default:
505     GNUNET_assert (0);
506   }
507 }
508
509
510 static void
511 run (void *cls,
512      const struct GNUNET_CONFIGURATION_Handle *cfg,
513      struct GNUNET_TESTING_Peer *peer)
514 {
515   struct CpsRunContext *crc;
516   static struct GNUNET_HashCode zkey;
517
518   crc = GNUNET_new (struct CpsRunContext);
519   crc->cfg = cfg;
520   crc->phase = RP_PUT;
521   now = GNUNET_TIME_absolute_get ();
522   datastore = GNUNET_DATASTORE_connect (cfg);
523   if (NULL ==
524       GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST",
525                             GNUNET_BLOCK_TYPE_TEST, 0, 0, 0,
526                             GNUNET_TIME_relative_to_absolute
527                             (GNUNET_TIME_UNIT_SECONDS), 0, 1,
528                             GNUNET_TIME_UNIT_MINUTES, &run_tests, crc))
529   {
530     FPRINTF (stderr, "%s",  "Test 'put' operation failed.\n");
531     ok = 1;
532     GNUNET_free (crc);
533   }
534 }
535
536
537 int
538 main (int argc, char *argv[])
539 {
540   char cfg_name[128];
541
542   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
543   GNUNET_snprintf (cfg_name, sizeof (cfg_name),
544                    "test_datastore_api_data_%s.conf", plugin_name);
545   if (0 !=
546       GNUNET_TESTING_peer_run ("test-gnunet-datastore",
547                                cfg_name,
548                                &run,
549                                NULL))
550     return 1;
551   return ok;
552 }
553
554 /* end of test_datastore_api.c */