getting mysql code to compile again, fixes to sqlite code
[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.abs_value = now.abs_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   const struct GNUNET_CONFIGURATION_Handle *cfg;
129   void *data;
130   size_t size;
131   enum RunPhase phase;
132   unsigned long long uid;
133 };
134
135
136 static void
137 run_continuation (void *cls,
138                   const struct GNUNET_SCHEDULER_TaskContext *tc);
139
140
141 static void
142 check_success (void *cls,
143                int success,
144                const char *msg)
145 {
146   struct CpsRunContext *crc = cls;
147   if (GNUNET_OK != success)
148     {
149       ok = 42;
150       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
151                   "%s\n", msg);
152       GNUNET_SCHEDULER_shutdown ();
153       return;
154     }
155   GNUNET_free_non_null (crc->data);
156   crc->data = NULL;
157   GNUNET_SCHEDULER_add_continuation (&run_continuation,
158                                      crc,
159                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
160 }
161
162
163 static void
164 get_reserved (void *cls,
165               int success,
166               const char *msg)
167 {
168   struct CpsRunContext *crc = cls;
169   if (0 >= success)
170     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171                 "%s\n", msg);
172   GNUNET_assert (0 < success);
173   crc->rid = success;
174   GNUNET_SCHEDULER_add_continuation (&run_continuation,
175                                      crc,
176                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
177 }
178
179
180 static void 
181 check_value (void *cls,
182              const 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
189              expiration, uint64_t uid)
190 {
191   static int matched;
192   struct CpsRunContext *crc = cls;
193   int i;
194
195   if (key == NULL)
196     {
197       if (crc->i == 0)
198         {
199           crc->phase = RP_DEL;
200           crc->i = ITERATIONS;
201         }
202       GNUNET_assert (matched == GNUNET_YES);
203       matched = GNUNET_NO;
204       GNUNET_SCHEDULER_add_continuation (&run_continuation,
205                                          crc,
206                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
207       return;
208     }
209   i = crc->i;
210   GNUNET_assert (size == get_size (i));
211   GNUNET_assert (0 == memcmp (data, get_data(i), size));
212   GNUNET_assert (type == get_type (i));
213   GNUNET_assert (priority == get_priority (i));
214   GNUNET_assert (anonymity == get_anonymity(i));
215   GNUNET_assert (expiration.abs_value == get_expiration(i).abs_value);
216   matched = GNUNET_YES;
217   GNUNET_DATASTORE_iterate_get_next (datastore);
218 }
219
220
221 static void 
222 delete_value (void *cls,
223               const GNUNET_HashCode * key,
224               size_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 (&run_continuation,
247                                          crc,
248                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
249       return;
250     }
251   GNUNET_assert (crc->data == NULL);
252   crc->size = size;
253   crc->key = *key;
254   crc->data = GNUNET_malloc (size);
255   memcpy (crc->data, data, size);
256   GNUNET_DATASTORE_iterate_get_next (datastore);
257 }
258
259
260 static void 
261 check_nothing (void *cls,
262                const GNUNET_HashCode * key,
263                size_t size,
264                const void *data,
265                enum GNUNET_BLOCK_Type type,
266                uint32_t priority,
267                uint32_t anonymity,
268                struct GNUNET_TIME_Absolute
269                expiration, uint64_t uid)
270 {
271   struct CpsRunContext *crc = cls;
272   GNUNET_assert (key == NULL);
273   if (crc->i == 0)
274     {
275       crc->phase = RP_RESERVE;    
276     }
277   GNUNET_SCHEDULER_add_continuation (&run_continuation,
278                                      crc,
279                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
280 }
281
282
283 static void 
284 check_multiple (void *cls,
285                 const GNUNET_HashCode * key,
286                 size_t size,
287                 const void *data,
288                 enum GNUNET_BLOCK_Type type,
289                 uint32_t priority,
290                 uint32_t anonymity,
291                 struct GNUNET_TIME_Absolute
292                 expiration, uint64_t uid)
293 {
294   struct CpsRunContext *crc = cls;
295
296   if (key == NULL)
297     {
298       if (crc->phase != RP_GET_MULTIPLE_DONE)
299         {
300           fprintf (stderr, 
301                    "Wrong phase: %d\n",
302                    crc->phase);
303           GNUNET_break (0);
304           crc->phase = RP_ERROR;
305         }
306       else
307         {
308           crc->phase = RP_UPDATE;
309         }
310       GNUNET_SCHEDULER_add_continuation (&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_iterate_get_next (datastore);
337 }
338
339
340 static void 
341 check_update (void *cls,
342               const GNUNET_HashCode * key,
343               size_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       if (crc->phase != RP_UPDATE_DONE)
356         {
357           GNUNET_break (0);
358           crc->phase = RP_ERROR;
359         }
360       else
361         {
362           crc->phase = RP_DONE;
363         }
364       GNUNET_SCHEDULER_add_continuation (&run_continuation,
365                                          crc,
366                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
367       return;
368     }
369   if ( (anonymity == get_anonymity (42)) &&
370        (size == get_size (42)) &&
371        (priority == get_priority (42) + 100) )
372     {
373       crc->phase = RP_UPDATE_DONE;
374     }
375   else
376     GNUNET_assert (size == get_size (43));
377   GNUNET_DATASTORE_iterate_get_next (datastore);
378 }
379
380
381 static void
382 run_continuation (void *cls,
383                   const struct GNUNET_SCHEDULER_TaskContext *tc)
384 {
385   struct CpsRunContext *crc = cls;
386   ok = (int) crc->phase;
387 #if VERBOSE
388   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389               "Test in phase %u\n", crc->phase);
390 #endif
391   switch (crc->phase)
392     {
393     case RP_PUT:
394 #if VERBOSE
395       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396                   "Executing `%s' number %u\n",
397                   "PUT",
398                   crc->i);
399 #endif
400       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
401       GNUNET_DATASTORE_put (datastore,
402                             0,
403                             &crc->key,
404                             get_size (crc->i),
405                             get_data (crc->i),
406                             get_type (crc->i),
407                             get_priority (crc->i),
408                             get_anonymity (crc->i),
409                             0,
410                             get_expiration (crc->i),
411                             1, 1, TIMEOUT,
412                             &check_success,
413                             crc);
414       crc->i++;
415       if (crc->i == ITERATIONS)
416         crc->phase = RP_GET;
417       break;
418     case RP_GET:
419       crc->i--;
420 #if VERBOSE
421       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
422                   "Executing `%s' number %u\n",
423                   "GET",
424                   crc->i);
425 #endif
426       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
427       GNUNET_DATASTORE_iterate_key (datastore, 
428                                     &crc->key,
429                                     get_type (crc->i),
430                                     1, 1, TIMEOUT,
431                                     &check_value,
432                                     crc);
433       break;
434     case RP_DEL:
435       crc->i--;
436 #if VERBOSE
437       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438                   "Executing `%s' number %u\n",
439                   "DEL",
440                   crc->i);
441 #endif
442       crc->data = NULL;
443       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
444       GNUNET_DATASTORE_iterate_key (datastore, 
445                                     &crc->key,
446                                     get_type (crc->i),
447                                     1, 1, TIMEOUT,
448                                     &delete_value,
449                                     crc);
450       break;
451     case RP_DO_DEL:
452 #if VERBOSE
453       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454                   "Executing `%s' number %u\n",
455                   "DO_DEL",
456                   crc->i);
457 #endif
458       if (crc->i == 0)
459         {
460           crc->i = ITERATIONS;   
461           crc->phase = RP_DELVALIDATE;
462         }      
463       else
464         {
465           crc->phase = RP_DEL;
466         }
467       GNUNET_DATASTORE_remove (datastore,
468                                &crc->key,
469                                crc->size,
470                                crc->data,
471                                1, 1, TIMEOUT,
472                                &check_success,
473                                crc);
474       break;   
475     case RP_DELVALIDATE:
476       crc->i--;
477 #if VERBOSE
478       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479                   "Executing `%s' number %u\n",
480                   "DEL-VALIDATE",
481                   crc->i);
482 #endif
483       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
484       GNUNET_DATASTORE_iterate_key (datastore, 
485                                     &crc->key,
486                                     get_type (crc->i),
487                                     1, 1, TIMEOUT,
488                                     &check_nothing,
489                                     crc);
490       break;
491     case RP_RESERVE:
492       crc->phase = RP_PUT_MULTIPLE;
493       GNUNET_DATASTORE_reserve (datastore,
494                                 128*1024,
495                                 2,
496                                 1, 1, TIMEOUT,
497                                 &get_reserved,
498                                 crc);
499       break;
500     case RP_PUT_MULTIPLE:
501       crc->phase = RP_PUT_MULTIPLE_NEXT;
502       GNUNET_DATASTORE_put (datastore,
503                             crc->rid,
504                             &crc->key,
505                             get_size (42),
506                             get_data (42),
507                             get_type (42),
508                             get_priority (42),
509                             get_anonymity (42),
510                             0,
511                             get_expiration (42),
512                             1, 1, TIMEOUT,
513                             &check_success,
514                             crc);
515       break;
516     case RP_PUT_MULTIPLE_NEXT:
517       crc->phase = RP_GET_MULTIPLE;
518       GNUNET_DATASTORE_put (datastore,
519                             crc->rid,
520                             &crc->key,
521                             get_size (43),
522                             get_data (43),
523                             get_type (42),
524                             get_priority (43),
525                             get_anonymity (43),
526                             0,
527                             get_expiration (43),
528                             1, 1, TIMEOUT,
529                             &check_success,
530                             crc);
531       break;
532     case RP_GET_MULTIPLE:
533       GNUNET_DATASTORE_iterate_key (datastore,
534                                     &crc->key, 
535                                     get_type (42),
536                                     1, 1, TIMEOUT,
537                                     &check_multiple,
538                                     crc);
539       break;
540     case RP_GET_MULTIPLE_NEXT:
541     case RP_GET_MULTIPLE_DONE:
542       GNUNET_assert (0);
543       break;
544     case RP_UPDATE:
545       GNUNET_assert (crc->uid > 0);
546       crc->phase = RP_UPDATE_VALIDATE;
547       GNUNET_DATASTORE_update (datastore,
548                                crc->uid,
549                                100,
550                                get_expiration (42),
551                                1, 1, TIMEOUT,
552                                &check_success,
553                                crc);
554       break;
555     case RP_UPDATE_VALIDATE:
556       GNUNET_DATASTORE_iterate_key (datastore,
557                                     &crc->key, 
558                                     get_type (42),
559                                     1, 1, TIMEOUT,
560                                     &check_update,
561                                     crc);   
562       break;
563     case RP_UPDATE_DONE:
564       GNUNET_assert (0);
565       break;
566     case RP_DONE:
567 #if VERBOSE
568       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569                   "Finished, disconnecting\n");
570 #endif
571       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
572       GNUNET_free (crc);
573       ok = 0;
574       break;
575     case RP_ERROR:
576       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
577       GNUNET_free (crc);
578       ok = 43;
579       break;
580     }
581 }
582
583
584 static void
585 run_tests (void *cls,
586            int32_t success,
587            const char *msg)
588 {
589   struct CpsRunContext *crc = cls;
590
591   switch (success)
592     {
593     case GNUNET_YES:
594       GNUNET_SCHEDULER_add_continuation (&run_continuation,
595                                          crc,
596                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
597       return;
598     case GNUNET_NO:
599       fprintf (stderr,
600                "Test 'put' operation failed, key already exists (!?)\n");
601       GNUNET_free (crc);
602       return;
603     case GNUNET_SYSERR:
604       fprintf (stderr,
605                "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
606                msg);
607       GNUNET_free (crc);
608       return;
609     default:
610       GNUNET_assert (0);
611     }
612 }
613
614
615 static void
616 run (void *cls,
617      char *const *args,
618      const char *cfgfile,
619      const struct GNUNET_CONFIGURATION_Handle *cfg)
620 {
621   struct CpsRunContext *crc;
622   static GNUNET_HashCode zkey;
623
624   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
625   crc->cfg = cfg;
626   crc->phase = RP_PUT;
627   now = GNUNET_TIME_absolute_get ();
628   datastore = GNUNET_DATASTORE_connect (cfg);
629   if (NULL ==
630       GNUNET_DATASTORE_put (datastore, 0,
631                             &zkey, 4, "TEST",
632                             GNUNET_BLOCK_TYPE_TEST,
633                             0, 0, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS),
634                             0, 1, GNUNET_TIME_UNIT_MINUTES,
635                             &run_tests, crc))
636     {
637       fprintf (stderr,
638                "Test 'put' operation failed.\n");
639       ok = 1;
640       GNUNET_free (crc);
641     }
642 }
643
644
645 static int
646 check ()
647 {
648   char cfg_name[128];
649 #if START_DATASTORE
650   struct GNUNET_OS_Process *proc;
651 #endif
652   char *const argv[] = {
653     "test-datastore-api",
654     "-c",
655     cfg_name,
656 #if VERBOSE
657     "-L", "DEBUG",
658 #endif
659     NULL
660   };
661   struct GNUNET_GETOPT_CommandLineOption options[] = {
662     GNUNET_GETOPT_OPTION_END
663   };
664   GNUNET_snprintf (cfg_name,
665                    sizeof (cfg_name),
666                    "test_datastore_api_data_%s.conf",
667                    plugin_name);
668 #if START_DATASTORE
669   proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
670                                  "gnunet-service-arm",
671 #if VERBOSE
672                                  "-L", "DEBUG",
673 #endif
674                                  "-c", cfg_name, NULL);
675 #endif
676   GNUNET_assert (NULL != proc);
677   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
678                       argv, "test-datastore-api", "nohelp",
679                       options, &run, NULL);
680 #if START_DATASTORE
681   if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
682     {
683       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
684       ok = 1;
685     }
686   GNUNET_OS_process_wait (proc);
687   GNUNET_OS_process_close (proc);
688   proc = NULL;
689 #endif
690   if (ok != 0)
691     fprintf (stderr, "Missed some testcases: %u\n", ok);
692   return ok;
693 }
694
695 int
696 main (int argc, char *argv[])
697 {
698   int ret;
699   char *pos;
700   char dir_name[128];
701
702   /* determine name of plugin to use */
703   plugin_name = argv[0];
704   while (NULL != (pos = strstr(plugin_name, "_")))
705     plugin_name = pos+1;
706   if (NULL != (pos = strstr(plugin_name, ".")))
707     pos[0] = 0;
708   else
709     pos = (char *) plugin_name;
710
711   GNUNET_snprintf (dir_name,
712                    sizeof (dir_name),
713                    "/tmp/test-gnunet-datastore-%s",
714                    plugin_name);
715   GNUNET_DISK_directory_remove (dir_name);
716   GNUNET_log_setup ("test-datastore-api",
717 #if VERBOSE
718                     "DEBUG",
719 #else
720                     "WARNING",
721 #endif
722                     NULL);
723   ret = check ();
724   if (pos != plugin_name)
725     pos[0] = '.';
726   GNUNET_DISK_directory_remove (dir_name);
727   return ret;
728 }
729
730 /* end of test_datastore_api.c */