fixes
[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
34 #define VERBOSE GNUNET_NO
35
36 #define START_DATASTORE GNUNET_NO
37
38 /**
39  * How long until we give up on transmitting the message?
40  */
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
42
43 #define ITERATIONS 256
44
45 static struct GNUNET_DATASTORE_Handle *datastore;
46
47 static struct GNUNET_TIME_Absolute now;
48
49 static int ok;
50
51 /**
52  * Name of plugin under test.
53  */
54 static const char *plugin_name;
55
56 static size_t
57 get_size (int i)
58 {
59   return 8 * i;
60 }
61
62
63 static const void *
64 get_data (int i)
65 {
66   static char buf[60000]; 
67   memset (buf, i, 8 * i);
68   return buf;
69 }
70
71
72 static int
73 get_type(int i)
74 {
75   return i+1;
76 }
77
78
79 static int 
80 get_priority (int i)
81 {
82   return i+1;
83 }
84
85
86 static int
87 get_anonymity(int i)
88 {
89   return i;
90 }
91
92
93 static struct GNUNET_TIME_Absolute 
94 get_expiration (int i)
95 {
96   struct GNUNET_TIME_Absolute av;
97
98   av.value = now.value + 20000000 - i * 1000;
99   return av;
100 }
101
102 enum RunPhase
103   {
104     RP_DONE = 0,
105     RP_PUT,
106     RP_GET,
107     RP_DEL,
108     RP_DO_DEL,
109     RP_DELVALIDATE,
110     RP_RESERVE,
111     RP_PUT_MULTIPLE,
112     RP_PUT_MULTIPLE_NEXT,
113     RP_GET_MULTIPLE,
114     RP_GET_MULTIPLE_NEXT,
115     RP_GET_MULTIPLE_DONE,
116     RP_UPDATE,
117     RP_UPDATE_VALIDATE,
118     RP_UPDATE_DONE,
119     RP_ERROR
120   };
121
122
123 struct CpsRunContext
124 {
125   GNUNET_HashCode key;
126   int i;
127   int rid;
128   struct GNUNET_SCHEDULER_Handle *sched;
129   const struct GNUNET_CONFIGURATION_Handle *cfg;
130   void *data;
131   size_t size;
132   enum RunPhase phase;
133   unsigned long long uid;
134 };
135
136
137 static void
138 run_continuation (void *cls,
139                   const struct GNUNET_SCHEDULER_TaskContext *tc);
140
141
142 static void
143 check_success (void *cls,
144                int success,
145                const char *msg)
146 {
147   struct CpsRunContext *crc = cls;
148   if (GNUNET_OK != success)
149     {
150       ok = 42;
151       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
152                   "%s\n", msg);
153       GNUNET_SCHEDULER_shutdown (crc->sched);
154       return;
155     }
156   GNUNET_free_non_null (crc->data);
157   crc->data = NULL;
158   GNUNET_SCHEDULER_add_continuation (crc->sched,
159                                      &run_continuation,
160                                      crc,
161                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
162 }
163
164
165 static void
166 get_reserved (void *cls,
167               int success,
168               const char *msg)
169 {
170   struct CpsRunContext *crc = cls;
171   if (0 >= success)
172     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
173                 "%s\n", msg);
174   GNUNET_assert (0 < success);
175   crc->rid = success;
176   GNUNET_SCHEDULER_add_continuation (crc->sched,
177                                      &run_continuation,
178                                      crc,
179                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
180 }
181
182
183 static void 
184 check_value (void *cls,
185              const GNUNET_HashCode * key,
186              uint32_t size,
187              const void *data,
188              enum GNUNET_BLOCK_Type type,
189              uint32_t priority,
190              uint32_t anonymity,
191              struct GNUNET_TIME_Absolute
192              expiration, uint64_t uid)
193 {
194   struct CpsRunContext *crc = cls;
195   int i;
196
197   if (key == NULL)
198     {
199       if (crc->i == 0)
200         {
201           crc->phase = RP_DEL;
202           crc->i = ITERATIONS;
203         }
204       GNUNET_SCHEDULER_add_continuation (crc->sched,
205                                          &run_continuation,
206                                          crc,
207                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
208       return;
209     }
210   i = crc->i;
211   GNUNET_assert (size == get_size (i));
212   GNUNET_assert (0 == memcmp (data, get_data(i), size));
213   GNUNET_assert (type == get_type (i));
214   GNUNET_assert (priority == get_priority (i));
215   GNUNET_assert (anonymity == get_anonymity(i));
216   GNUNET_assert (expiration.value == get_expiration(i).value);
217   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
218 }
219
220
221 static void 
222 delete_value (void *cls,
223               const GNUNET_HashCode * key,
224               uint32_t size,
225               const void *data,
226               enum GNUNET_BLOCK_Type type,
227               uint32_t priority,
228               uint32_t anonymity,
229               struct GNUNET_TIME_Absolute
230               expiration, uint64_t uid)
231 {
232   struct CpsRunContext *crc = cls;
233   if (key == NULL)
234     {
235       if (crc->data == NULL)
236         {
237           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
238                       "Content %u not found!\n",
239                       crc->i);
240           crc->phase = RP_ERROR;
241         }
242       else
243         {
244           crc->phase = RP_DO_DEL;
245         }
246       GNUNET_SCHEDULER_add_continuation (crc->sched,
247                                          &run_continuation,
248                                          crc,
249                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
250       return;
251     }
252   GNUNET_assert (crc->data == NULL);
253   crc->size = size;
254   crc->key = *key;
255   crc->data = GNUNET_malloc (size);
256   memcpy (crc->data, data, size);
257   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
258 }
259
260
261 static void 
262 check_nothing (void *cls,
263                const GNUNET_HashCode * key,
264                uint32_t size,
265                const void *data,
266                enum GNUNET_BLOCK_Type type,
267                uint32_t priority,
268                uint32_t anonymity,
269                struct GNUNET_TIME_Absolute
270                expiration, uint64_t uid)
271 {
272   struct CpsRunContext *crc = cls;
273   GNUNET_assert (key == NULL);
274   if (crc->i == 0)
275     {
276       crc->phase = RP_RESERVE;    
277     }
278   GNUNET_SCHEDULER_add_continuation (crc->sched,
279                                      &run_continuation,
280                                      crc,
281                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
282 }
283
284
285 static void 
286 check_multiple (void *cls,
287                 const GNUNET_HashCode * key,
288                 uint32_t size,
289                 const void *data,
290                 enum GNUNET_BLOCK_Type type,
291                 uint32_t priority,
292                 uint32_t anonymity,
293                 struct GNUNET_TIME_Absolute
294                 expiration, uint64_t uid)
295 {
296   struct CpsRunContext *crc = cls;
297
298   if (key == NULL)
299     {
300       if (crc->phase != RP_GET_MULTIPLE_DONE)
301         {
302           GNUNET_break (0);
303           crc->phase = RP_ERROR;
304         }
305       else
306         {
307           crc->phase = RP_UPDATE;
308         }
309       GNUNET_SCHEDULER_add_continuation (crc->sched,
310                                          &run_continuation,
311                                          crc,
312                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
313       return;
314     }
315   switch (crc->phase)
316     {
317     case RP_GET_MULTIPLE:
318       crc->phase = RP_GET_MULTIPLE_NEXT;
319       break;
320     case RP_GET_MULTIPLE_NEXT:
321       crc->phase = RP_GET_MULTIPLE_DONE;
322       break;
323     case RP_GET_MULTIPLE_DONE:
324       /* do not advance further */
325       break;
326     default:
327       GNUNET_break (0);
328       break;
329     }
330 #if VERBOSE
331   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332               "Test in phase %u\n", crc->phase);
333 #endif
334   if (priority == get_priority (42))
335     crc->uid = uid;
336   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
337 }
338
339
340 static void 
341 check_update (void *cls,
342               const GNUNET_HashCode * key,
343               uint32_t size,
344               const void *data,
345               enum GNUNET_BLOCK_Type type,
346               uint32_t priority,
347               uint32_t anonymity,
348               struct GNUNET_TIME_Absolute
349               expiration, uint64_t uid)
350 {
351   struct CpsRunContext *crc = cls;
352
353   if (key == NULL)
354     {
355       GNUNET_assert (crc->phase == RP_UPDATE_DONE);
356       crc->phase = RP_DONE;
357       GNUNET_SCHEDULER_add_continuation (crc->sched,
358                                          &run_continuation,
359                                          crc,
360                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
361       return;
362     }
363   if ( (anonymity == get_anonymity (42)) &&
364        (size == get_size (42)) &&
365        (priority == get_priority (42) + 100) )
366     {
367       crc->phase = RP_UPDATE_DONE;
368     }
369   else
370     GNUNET_assert (size == get_size (43));
371   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
372 }
373
374
375 static void
376 run_continuation (void *cls,
377                   const struct GNUNET_SCHEDULER_TaskContext *tc)
378 {
379   struct CpsRunContext *crc = cls;
380   ok = (int) crc->phase;
381 #if VERBOSE
382   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383               "Test in phase %u\n", crc->phase);
384 #endif
385   switch (crc->phase)
386     {
387     case RP_PUT:
388 #if VERBOSE
389       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390                   "Executing `%s' number %u\n",
391                   "PUT",
392                   crc->i);
393 #endif
394       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
395       GNUNET_DATASTORE_put (datastore,
396                             0,
397                             &crc->key,
398                             get_size (crc->i),
399                             get_data (crc->i),
400                             get_type (crc->i),
401                             get_priority (crc->i),
402                             get_anonymity (crc->i),
403                             get_expiration (crc->i),
404                             1, 1, TIMEOUT,
405                             &check_success,
406                             crc);
407       crc->i++;
408       if (crc->i == ITERATIONS)
409         crc->phase = RP_GET;
410       break;
411     case RP_GET:
412       crc->i--;
413 #if VERBOSE
414       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415                   "Executing `%s' number %u\n",
416                   "GET",
417                   crc->i);
418 #endif
419       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
420       GNUNET_DATASTORE_get (datastore, 
421                             &crc->key,
422                             get_type (crc->i),
423                             1, 1, TIMEOUT,
424                             &check_value,
425                             crc);
426       break;
427     case RP_DEL:
428       crc->i--;
429 #if VERBOSE
430       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431                   "Executing `%s' number %u\n",
432                   "DEL",
433                   crc->i);
434 #endif
435       crc->data = NULL;
436       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
437       GNUNET_DATASTORE_get (datastore, 
438                             &crc->key,
439                             get_type (crc->i),
440                             1, 1, TIMEOUT,
441                             &delete_value,
442                             crc);
443       break;
444     case RP_DO_DEL:
445 #if VERBOSE
446       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447                   "Executing `%s' number %u\n",
448                   "DO_DEL",
449                   crc->i);
450 #endif
451       if (crc->i == 0)
452         {
453           crc->i = ITERATIONS;   
454           crc->phase = RP_DELVALIDATE;
455         }      
456       else
457         {
458           crc->phase = RP_DEL;
459         }
460       GNUNET_DATASTORE_remove (datastore,
461                                &crc->key,
462                                crc->size,
463                                crc->data,
464                                1, 1, TIMEOUT,
465                                &check_success,
466                                crc);
467       break;   
468     case RP_DELVALIDATE:
469       crc->i--;
470 #if VERBOSE
471       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472                   "Executing `%s' number %u\n",
473                   "DEL-VALIDATE",
474                   crc->i);
475 #endif
476       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
477       GNUNET_DATASTORE_get (datastore, 
478                             &crc->key,
479                             get_type (crc->i),
480                             1, 1, TIMEOUT,
481                             &check_nothing,
482                             crc);
483       break;
484     case RP_RESERVE:
485       crc->phase = RP_PUT_MULTIPLE;
486       GNUNET_DATASTORE_reserve (datastore,
487                                 128*1024,
488                                 2,
489                                 1, 1, TIMEOUT,
490                                 &get_reserved,
491                                 crc);
492       break;
493     case RP_PUT_MULTIPLE:
494       crc->phase = RP_PUT_MULTIPLE_NEXT;
495       GNUNET_DATASTORE_put (datastore,
496                             crc->rid,
497                             &crc->key,
498                             get_size (42),
499                             get_data (42),
500                             get_type (42),
501                             get_priority (42),
502                             get_anonymity (42),
503                             get_expiration (42),
504                             1, 1, TIMEOUT,
505                             &check_success,
506                             crc);
507       break;
508     case RP_PUT_MULTIPLE_NEXT:
509       crc->phase = RP_GET_MULTIPLE;
510       GNUNET_DATASTORE_put (datastore,
511                             crc->rid,
512                             &crc->key,
513                             get_size (43),
514                             get_data (43),
515                             get_type (42),
516                             get_priority (43),
517                             get_anonymity (43),
518                             get_expiration (43),
519                             1, 1, TIMEOUT,
520                             &check_success,
521                             crc);
522       break;
523     case RP_GET_MULTIPLE:
524       GNUNET_DATASTORE_get (datastore,
525                             &crc->key, 
526                             get_type (42),
527                             1, 1, TIMEOUT,
528                             &check_multiple,
529                             crc);
530       break;
531     case RP_GET_MULTIPLE_NEXT:
532     case RP_GET_MULTIPLE_DONE:
533       GNUNET_assert (0);
534       break;
535     case RP_UPDATE:
536       GNUNET_assert (crc->uid > 0);
537       crc->phase = RP_UPDATE_VALIDATE;
538       GNUNET_DATASTORE_update (datastore,
539                                crc->uid,
540                                100,
541                                get_expiration (42),
542                                1, 1, TIMEOUT,
543                                &check_success,
544                                crc);
545       break;
546     case RP_UPDATE_VALIDATE:
547       GNUNET_DATASTORE_get (datastore,
548                             &crc->key, 
549                             get_type (42),
550                             1, 1, TIMEOUT,
551                             &check_update,
552                             crc);   
553       break;
554     case RP_UPDATE_DONE:
555       GNUNET_assert (0);
556       break;
557     case RP_DONE:
558 #if VERBOSE
559       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560                   "Finished, disconnecting\n");
561 #endif
562       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
563       GNUNET_free (crc);
564       ok = 0;
565       break;
566     case RP_ERROR:
567       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
568       GNUNET_free (crc);
569       ok = 43;
570       break;
571     }
572 }
573
574
575 static void
576 run (void *cls,
577      struct GNUNET_SCHEDULER_Handle *sched,
578      char *const *args,
579      const char *cfgfile,
580      const struct GNUNET_CONFIGURATION_Handle *cfg)
581 {
582   struct CpsRunContext *crc;
583
584   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
585   crc->sched = sched;
586   crc->cfg = cfg;
587   crc->phase = RP_PUT;
588   now = GNUNET_TIME_absolute_get ();
589   datastore = GNUNET_DATASTORE_connect (cfg, sched);
590   GNUNET_SCHEDULER_add_continuation (crc->sched,
591                                      &run_continuation,
592                                      crc,
593                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
594
595 }
596
597
598
599 static int
600 check ()
601 {
602   char cfg_name[128];
603 #if START_DATASTORE
604   pid_t pid;
605 #endif
606   char *const argv[] = {
607     "test-datastore-api",
608     "-c",
609     cfg_name,
610 #if VERBOSE
611     "-L", "DEBUG",
612 #endif
613     NULL
614   };
615   struct GNUNET_GETOPT_CommandLineOption options[] = {
616     GNUNET_GETOPT_OPTION_END
617   };
618   GNUNET_snprintf (cfg_name,
619                    sizeof (cfg_name),
620                    "test_datastore_api_data_%s.conf",
621                    plugin_name);
622 #if START_DATASTORE
623   pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
624                                  "gnunet-service-arm",
625 #if VERBOSE
626                                  "-L", "DEBUG",
627 #endif
628                                  "-c", cfg_name, NULL);
629 #endif
630   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
631                       argv, "test-datastore-api", "nohelp",
632                       options, &run, NULL);
633 #if START_DATASTORE
634   if (0 != PLIBC_KILL (pid, SIGTERM))
635     {
636       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
637       ok = 1;
638     }
639   GNUNET_OS_process_wait(pid);
640 #endif
641   if (ok != 0)
642     fprintf (stderr, "Missed some testcases: %u\n", ok);
643   return ok;
644 }
645
646 int
647 main (int argc, char *argv[])
648 {
649   int ret;
650   const char *pos;
651   char dir_name[128];
652
653   /* determine name of plugin to use */
654   plugin_name = argv[0];
655   while (NULL != (pos = strstr(plugin_name, "_")))
656     plugin_name = pos+1;
657
658   GNUNET_snprintf (dir_name,
659                    sizeof (dir_name),
660                    "/tmp/test-gnunet-datastore-%s",
661                    plugin_name);
662   GNUNET_DISK_directory_remove (dir_name);
663   GNUNET_log_setup ("test-datastore-api",
664 #if VERBOSE
665                     "DEBUG",
666 #else
667                     "WARNING",
668 #endif
669                     NULL);
670   ret = check ();
671   GNUNET_DISK_directory_remove (dir_name);
672   return ret;
673 }
674
675 /* end of test_datastore_api.c */