add nick name for cached records
[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, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg)
141 {
142   struct CpsRunContext *crc = cls;
143
144   if (GNUNET_OK != success)
145   {
146     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
147                 "Operation %d/%d not successfull: `%s'\n", crc->phase, crc->i,
148                 msg);
149     crc->phase = RP_ERROR;
150   }
151   GNUNET_free_non_null (crc->data);
152   crc->data = NULL;
153   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
154                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
155 }
156
157
158 static void
159 get_reserved (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg)
160 {
161   struct CpsRunContext *crc = cls;
162
163   if (0 >= success)
164     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error obtaining reservation: `%s'\n",
165                 msg);
166   GNUNET_assert (0 < success);
167   crc->rid = success;
168   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
169                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
170 }
171
172
173 static void
174 check_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
175              const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
176              uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
177              uint64_t uid)
178 {
179   struct CpsRunContext *crc = cls;
180   int i;
181
182   i = crc->i;
183   if (NULL == key)
184   {
185     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186                 "Value check failed (got NULL key) in %d/%d\n", crc->phase,
187                 crc->i);
188     crc->phase = RP_ERROR;
189     GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
190                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
191     return;
192   }
193 #if 0
194   FPRINTF (stderr,
195            "Check value got `%s' of size %u, type %d, expire %s\n",
196            GNUNET_h2s (key), (unsigned int) size, type,
197            GNUNET_STRINGS_absolute_time_to_string (expiration));
198   FPRINTF (stderr,
199            "Check value iteration %d wants size %u, type %d, expire %s\n", i,
200            (unsigned int) get_size (i), get_type (i),
201            GNUNET_STRINGS_absolute_time_to_string (get_expiration(i)));
202 #endif
203   GNUNET_assert (size == get_size (i));
204   GNUNET_assert (0 == memcmp (data, get_data (i), size));
205   GNUNET_assert (type == get_type (i));
206   GNUNET_assert (priority == get_priority (i));
207   GNUNET_assert (anonymity == get_anonymity (i));
208   GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
209   crc->offset++;
210   if (crc->i == 0)
211   {
212     crc->phase = RP_DEL;
213     crc->i = ITERATIONS;
214   }
215   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
216                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
217 }
218
219
220 static void
221 delete_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
222               const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
223               uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
224               uint64_t uid)
225 {
226   struct CpsRunContext *crc = cls;
227
228   GNUNET_assert (crc->data == NULL);
229   GNUNET_assert (NULL != key);
230   crc->size = size;
231   crc->key = *key;
232   crc->data = GNUNET_malloc (size);
233   memcpy (crc->data, data, size);
234   crc->phase = RP_DO_DEL;
235   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
236                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
237 }
238
239
240 static void
241 check_nothing (void *cls, const struct GNUNET_HashCode * key, size_t size,
242                const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
243                uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
244                uint64_t uid)
245 {
246   struct CpsRunContext *crc = cls;
247
248   GNUNET_assert (key == NULL);
249   if (crc->i == 0)
250     crc->phase = RP_RESERVE;
251   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
252                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
253 }
254
255
256 static void
257 check_multiple (void *cls, const struct GNUNET_HashCode * key, size_t size,
258                 const void *data, enum GNUNET_BLOCK_Type type,
259                 uint32_t priority, uint32_t anonymity,
260                 struct GNUNET_TIME_Absolute expiration, uint64_t uid)
261 {
262   struct CpsRunContext *crc = cls;
263
264   GNUNET_assert (key != NULL);
265   switch (crc->phase)
266   {
267   case RP_GET_MULTIPLE:
268     crc->phase = RP_GET_MULTIPLE_NEXT;
269     crc->first_uid = uid;
270     crc->offset++;
271     break;
272   case RP_GET_MULTIPLE_NEXT:
273     GNUNET_assert (uid != crc->first_uid);
274     crc->phase = RP_UPDATE;
275     break;
276   default:
277     GNUNET_break (0);
278     crc->phase = RP_ERROR;
279     break;
280   }
281   if (priority == get_priority (42))
282     crc->uid = uid;
283   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
284                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
285 }
286
287
288 static void
289 check_update (void *cls, const struct GNUNET_HashCode * key, size_t size,
290               const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
291               uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
292               uint64_t uid)
293 {
294   struct CpsRunContext *crc = cls;
295
296   GNUNET_assert (key != NULL);
297   if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
298       (priority == get_priority (42) + 100))
299     crc->phase = RP_DONE;
300   else
301   {
302     GNUNET_assert (size == get_size (43));
303     crc->offset++;
304   }
305   GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
306                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
307 }
308
309
310 static void
311 run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
312 {
313   struct CpsRunContext *crc = cls;
314
315   ok = (int) crc->phase;
316   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test in phase %u\n", crc->phase);
317   switch (crc->phase)
318   {
319   case RP_PUT:
320     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT",
321                 crc->i);
322     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
323     GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
324                           get_data (crc->i), get_type (crc->i),
325                           get_priority (crc->i), get_anonymity (crc->i), 0,
326                           get_expiration (crc->i), 1, 1, TIMEOUT,
327                           &check_success, crc);
328     crc->i++;
329     if (crc->i == ITERATIONS)
330       crc->phase = RP_GET;
331     break;
332   case RP_GET:
333     crc->i--;
334     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET",
335                 crc->i);
336     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
337     GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
338                               get_type (crc->i), 1, 1, TIMEOUT, &check_value,
339                               crc);
340     break;
341   case RP_DEL:
342     crc->i--;
343     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DEL",
344                 crc->i);
345     crc->data = NULL;
346     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
347     GNUNET_assert (NULL !=
348                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
349                                              get_type (crc->i), 1, 1, TIMEOUT,
350                                              &delete_value, crc));
351     break;
352   case RP_DO_DEL:
353     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DO_DEL",
354                 crc->i);
355     if (crc->i == 0)
356     {
357       crc->i = ITERATIONS;
358       crc->phase = RP_DELVALIDATE;
359     }
360     else
361     {
362       crc->phase = RP_DEL;
363     }
364     GNUNET_assert (NULL !=
365                    GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
366                                             crc->data, 1, 1, TIMEOUT,
367                                             &check_success, crc));
368     break;
369   case RP_DELVALIDATE:
370     crc->i--;
371     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n",
372                 "DEL-VALIDATE", crc->i);
373     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
374     GNUNET_assert (NULL !=
375                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
376                                              get_type (crc->i), 1, 1, TIMEOUT,
377                                              &check_nothing, crc));
378     break;
379   case RP_RESERVE:
380     crc->phase = RP_PUT_MULTIPLE;
381     GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2, 1, 1, TIMEOUT,
382                               &get_reserved, crc);
383     break;
384   case RP_PUT_MULTIPLE:
385     crc->phase = RP_PUT_MULTIPLE_NEXT;
386     GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
387                           get_data (42), get_type (42), get_priority (42),
388                           get_anonymity (42), 0, get_expiration (42), 1, 1,
389                           TIMEOUT, &check_success, crc);
390     break;
391   case RP_PUT_MULTIPLE_NEXT:
392     crc->phase = RP_GET_MULTIPLE;
393     GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (43),
394                           get_data (43), get_type (42), get_priority (43),
395                           get_anonymity (43), 0, get_expiration (43), 1, 1,
396                           TIMEOUT, &check_success, crc);
397     break;
398   case RP_GET_MULTIPLE:
399     GNUNET_assert (NULL !=
400                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
401                                              get_type (42), 1, 1, TIMEOUT,
402                                              &check_multiple, crc));
403     break;
404   case RP_GET_MULTIPLE_NEXT:
405     GNUNET_assert (NULL !=
406                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
407                                              get_type (42), 1, 1, TIMEOUT,
408                                              &check_multiple, crc));
409     break;
410   case RP_UPDATE:
411     GNUNET_assert (crc->uid > 0);
412     crc->phase = RP_UPDATE_VALIDATE;
413     GNUNET_DATASTORE_update (datastore, crc->uid, 100, get_expiration (42), 1,
414                              1, TIMEOUT, &check_success, crc);
415     break;
416   case RP_UPDATE_VALIDATE:
417     GNUNET_assert (NULL !=
418                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
419                                              get_type (42), 1, 1, TIMEOUT,
420                                              &check_update, crc));
421     break;
422   case RP_DONE:
423     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n");
424     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
425     GNUNET_free (crc);
426     ok = 0;
427     break;
428   case RP_ERROR:
429     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
430     GNUNET_free (crc);
431     ok = 43;
432     break;
433   }
434 }
435
436
437 static void
438 run_tests (void *cls, int32_t success, struct GNUNET_TIME_Absolute min_expiration, const char *msg)
439 {
440   struct CpsRunContext *crc = cls;
441
442   switch (success)
443   {
444   case GNUNET_YES:
445     GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
446                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
447     return;
448   case GNUNET_NO:
449     FPRINTF (stderr, "%s", "Test 'put' operation failed, key already exists (!?)\n");
450     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
451     GNUNET_free (crc);
452     return;
453   case GNUNET_SYSERR:
454     FPRINTF (stderr,
455              "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
456              msg);
457     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
458     GNUNET_free (crc);
459     return;
460   default:
461     GNUNET_assert (0);
462   }
463 }
464
465
466 static void
467 run (void *cls,
468      const struct GNUNET_CONFIGURATION_Handle *cfg,
469      struct GNUNET_TESTING_Peer *peer)
470 {
471   struct CpsRunContext *crc;
472   static struct GNUNET_HashCode zkey;
473
474   crc = GNUNET_malloc (sizeof (struct CpsRunContext));
475   crc->cfg = cfg;
476   crc->phase = RP_PUT;
477   now = GNUNET_TIME_absolute_get ();
478   datastore = GNUNET_DATASTORE_connect (cfg);
479   if (NULL ==
480       GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST",
481                             GNUNET_BLOCK_TYPE_TEST, 0, 0, 0,
482                             GNUNET_TIME_relative_to_absolute
483                             (GNUNET_TIME_UNIT_SECONDS), 0, 1,
484                             GNUNET_TIME_UNIT_MINUTES, &run_tests, crc))
485   {
486     FPRINTF (stderr, "%s",  "Test 'put' operation failed.\n");
487     ok = 1;
488     GNUNET_free (crc);
489   }
490 }
491
492
493 int
494 main (int argc, char *argv[])
495 {
496   char cfg_name[128];
497
498   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
499   GNUNET_snprintf (cfg_name, sizeof (cfg_name),
500                    "test_datastore_api_data_%s.conf", plugin_name);
501   if (0 !=
502       GNUNET_TESTING_peer_run ("test-gnunet-datastore",
503                                cfg_name,
504                                &run,
505                                NULL))
506     return 1;
507   return ok;
508 }
509
510 /* end of test_datastore_api.c */