getting mysql to work
[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_YES
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, /* 10 */
115     RP_GET_MULTIPLE_DONE,
116     RP_UPDATE,
117     RP_UPDATE_VALIDATE, /* 13 */
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           fprintf (stderr, 
303                    "Wrong phase: %d\n",
304                    crc->phase);
305           GNUNET_break (0);
306           crc->phase = RP_ERROR;
307         }
308       else
309         {
310           crc->phase = RP_UPDATE;
311         }
312       GNUNET_SCHEDULER_add_continuation (crc->sched,
313                                          &run_continuation,
314                                          crc,
315                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
316       return;
317     }
318   switch (crc->phase)
319     {
320     case RP_GET_MULTIPLE:
321       crc->phase = RP_GET_MULTIPLE_NEXT;
322       break;
323     case RP_GET_MULTIPLE_NEXT:
324       crc->phase = RP_GET_MULTIPLE_DONE;
325       break;
326     case RP_GET_MULTIPLE_DONE:
327       /* do not advance further */
328       break;
329     default:
330       GNUNET_break (0);
331       break;
332     }
333 #if VERBOSE
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "Test in phase %u\n", crc->phase);
336 #endif
337   if (priority == get_priority (42))
338     crc->uid = uid;
339   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
340 }
341
342
343 static void 
344 check_update (void *cls,
345               const GNUNET_HashCode * key,
346               uint32_t size,
347               const void *data,
348               enum GNUNET_BLOCK_Type type,
349               uint32_t priority,
350               uint32_t anonymity,
351               struct GNUNET_TIME_Absolute
352               expiration, uint64_t uid)
353 {
354   struct CpsRunContext *crc = cls;
355
356   if (key == NULL)
357     {
358       if (crc->phase != RP_UPDATE_DONE)
359         {
360           GNUNET_break (0);
361           crc->phase = RP_ERROR;
362         }
363       else
364         {
365           crc->phase = RP_DONE;
366         }
367       GNUNET_SCHEDULER_add_continuation (crc->sched,
368                                          &run_continuation,
369                                          crc,
370                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
371       return;
372     }
373   if ( (anonymity == get_anonymity (42)) &&
374        (size == get_size (42)) &&
375        (priority == get_priority (42) + 100) )
376     {
377       crc->phase = RP_UPDATE_DONE;
378     }
379   else
380     GNUNET_assert (size == get_size (43));
381   GNUNET_DATASTORE_get_next (datastore, GNUNET_YES);
382 }
383
384
385 static void
386 run_continuation (void *cls,
387                   const struct GNUNET_SCHEDULER_TaskContext *tc)
388 {
389   struct CpsRunContext *crc = cls;
390   ok = (int) crc->phase;
391 #if VERBOSE
392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393               "Test in phase %u\n", crc->phase);
394 #endif
395   switch (crc->phase)
396     {
397     case RP_PUT:
398 #if VERBOSE
399       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400                   "Executing `%s' number %u\n",
401                   "PUT",
402                   crc->i);
403 #endif
404       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
405       GNUNET_DATASTORE_put (datastore,
406                             0,
407                             &crc->key,
408                             get_size (crc->i),
409                             get_data (crc->i),
410                             get_type (crc->i),
411                             get_priority (crc->i),
412                             get_anonymity (crc->i),
413                             get_expiration (crc->i),
414                             1, 1, TIMEOUT,
415                             &check_success,
416                             crc);
417       crc->i++;
418       if (crc->i == ITERATIONS)
419         crc->phase = RP_GET;
420       break;
421     case RP_GET:
422       crc->i--;
423 #if VERBOSE
424       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425                   "Executing `%s' number %u\n",
426                   "GET",
427                   crc->i);
428 #endif
429       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
430       GNUNET_DATASTORE_get (datastore, 
431                             &crc->key,
432                             get_type (crc->i),
433                             1, 1, TIMEOUT,
434                             &check_value,
435                             crc);
436       break;
437     case RP_DEL:
438       crc->i--;
439 #if VERBOSE
440       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
441                   "Executing `%s' number %u\n",
442                   "DEL",
443                   crc->i);
444 #endif
445       crc->data = NULL;
446       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
447       GNUNET_DATASTORE_get (datastore, 
448                             &crc->key,
449                             get_type (crc->i),
450                             1, 1, TIMEOUT,
451                             &delete_value,
452                             crc);
453       break;
454     case RP_DO_DEL:
455 #if VERBOSE
456       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457                   "Executing `%s' number %u\n",
458                   "DO_DEL",
459                   crc->i);
460 #endif
461       if (crc->i == 0)
462         {
463           crc->i = ITERATIONS;   
464           crc->phase = RP_DELVALIDATE;
465         }      
466       else
467         {
468           crc->phase = RP_DEL;
469         }
470       GNUNET_DATASTORE_remove (datastore,
471                                &crc->key,
472                                crc->size,
473                                crc->data,
474                                1, 1, TIMEOUT,
475                                &check_success,
476                                crc);
477       break;   
478     case RP_DELVALIDATE:
479       crc->i--;
480 #if VERBOSE
481       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482                   "Executing `%s' number %u\n",
483                   "DEL-VALIDATE",
484                   crc->i);
485 #endif
486       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
487       GNUNET_DATASTORE_get (datastore, 
488                             &crc->key,
489                             get_type (crc->i),
490                             1, 1, TIMEOUT,
491                             &check_nothing,
492                             crc);
493       break;
494     case RP_RESERVE:
495       crc->phase = RP_PUT_MULTIPLE;
496       GNUNET_DATASTORE_reserve (datastore,
497                                 128*1024,
498                                 2,
499                                 1, 1, TIMEOUT,
500                                 &get_reserved,
501                                 crc);
502       break;
503     case RP_PUT_MULTIPLE:
504       crc->phase = RP_PUT_MULTIPLE_NEXT;
505       GNUNET_DATASTORE_put (datastore,
506                             crc->rid,
507                             &crc->key,
508                             get_size (42),
509                             get_data (42),
510                             get_type (42),
511                             get_priority (42),
512                             get_anonymity (42),
513                             get_expiration (42),
514                             1, 1, TIMEOUT,
515                             &check_success,
516                             crc);
517       break;
518     case RP_PUT_MULTIPLE_NEXT:
519       crc->phase = RP_GET_MULTIPLE;
520       GNUNET_DATASTORE_put (datastore,
521                             crc->rid,
522                             &crc->key,
523                             get_size (43),
524                             get_data (43),
525                             get_type (42),
526                             get_priority (43),
527                             get_anonymity (43),
528                             get_expiration (43),
529                             1, 1, TIMEOUT,
530                             &check_success,
531                             crc);
532       break;
533     case RP_GET_MULTIPLE:
534       GNUNET_DATASTORE_get (datastore,
535                             &crc->key, 
536                             get_type (42),
537                             1, 1, TIMEOUT,
538                             &check_multiple,
539                             crc);
540       break;
541     case RP_GET_MULTIPLE_NEXT:
542     case RP_GET_MULTIPLE_DONE:
543       GNUNET_assert (0);
544       break;
545     case RP_UPDATE:
546       GNUNET_assert (crc->uid > 0);
547       crc->phase = RP_UPDATE_VALIDATE;
548       GNUNET_DATASTORE_update (datastore,
549                                crc->uid,
550                                100,
551                                get_expiration (42),
552                                1, 1, TIMEOUT,
553                                &check_success,
554                                crc);
555       break;
556     case RP_UPDATE_VALIDATE:
557       GNUNET_DATASTORE_get (datastore,
558                             &crc->key, 
559                             get_type (42),
560                             1, 1, TIMEOUT,
561                             &check_update,
562                             crc);   
563       break;
564     case RP_UPDATE_DONE:
565       GNUNET_assert (0);
566       break;
567     case RP_DONE:
568 #if VERBOSE
569       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570                   "Finished, disconnecting\n");
571 #endif
572       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
573       GNUNET_free (crc);
574       ok = 0;
575       break;
576     case RP_ERROR:
577       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
578       GNUNET_free (crc);
579       ok = 43;
580       break;
581     }
582 }
583
584
585 static void
586 run (void *cls,
587      struct GNUNET_SCHEDULER_Handle *sched,
588      char *const *args,
589      const char *cfgfile,
590      const struct GNUNET_CONFIGURATION_Handle *cfg)
591 {
592   struct CpsRunContext *crc;
593
594   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
595   crc->sched = sched;
596   crc->cfg = cfg;
597   crc->phase = RP_PUT;
598   now = GNUNET_TIME_absolute_get ();
599   datastore = GNUNET_DATASTORE_connect (cfg, sched);
600   GNUNET_SCHEDULER_add_continuation (crc->sched,
601                                      &run_continuation,
602                                      crc,
603                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
604
605 }
606
607
608
609 static int
610 check ()
611 {
612   char cfg_name[128];
613 #if START_DATASTORE
614   pid_t pid;
615 #endif
616   char *const argv[] = {
617     "test-datastore-api",
618     "-c",
619     cfg_name,
620 #if VERBOSE
621     "-L", "DEBUG",
622 #endif
623     NULL
624   };
625   struct GNUNET_GETOPT_CommandLineOption options[] = {
626     GNUNET_GETOPT_OPTION_END
627   };
628   GNUNET_snprintf (cfg_name,
629                    sizeof (cfg_name),
630                    "test_datastore_api_data_%s.conf",
631                    plugin_name);
632 #if START_DATASTORE
633   pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
634                                  "gnunet-service-arm",
635 #if VERBOSE
636                                  "-L", "DEBUG",
637 #endif
638                                  "-c", cfg_name, NULL);
639 #endif
640   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
641                       argv, "test-datastore-api", "nohelp",
642                       options, &run, NULL);
643 #if START_DATASTORE
644   if (0 != PLIBC_KILL (pid, SIGTERM))
645     {
646       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
647       ok = 1;
648     }
649   GNUNET_OS_process_wait(pid);
650 #endif
651   if (ok != 0)
652     fprintf (stderr, "Missed some testcases: %u\n", ok);
653   return ok;
654 }
655
656 int
657 main (int argc, char *argv[])
658 {
659   int ret;
660   const char *pos;
661   char dir_name[128];
662
663   /* determine name of plugin to use */
664   plugin_name = argv[0];
665   while (NULL != (pos = strstr(plugin_name, "_")))
666     plugin_name = pos+1;
667
668   GNUNET_snprintf (dir_name,
669                    sizeof (dir_name),
670                    "/tmp/test-gnunet-datastore-%s",
671                    plugin_name);
672   GNUNET_DISK_directory_remove (dir_name);
673   GNUNET_log_setup ("test-datastore-api",
674 #if VERBOSE
675                     "DEBUG",
676 #else
677                     "WARNING",
678 #endif
679                     NULL);
680   ret = check ();
681   GNUNET_DISK_directory_remove (dir_name);
682   return ret;
683 }
684
685 /* end of test_datastore_api.c */