mysql 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_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                   "Operation not successfull: `%s'\n", msg);
152       crc->phase = RP_ERROR;
153       GNUNET_SCHEDULER_add_continuation (&run_continuation,
154                                          crc,
155                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
156       return;
157     }
158   GNUNET_free_non_null (crc->data);
159   crc->data = NULL;
160   GNUNET_SCHEDULER_add_continuation (&run_continuation,
161                                      crc,
162                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
163 }
164
165
166 static void
167 get_reserved (void *cls,
168               int success,
169               const char *msg)
170 {
171   struct CpsRunContext *crc = cls;
172   if (0 >= success)
173     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174                 "%s\n", msg);
175   GNUNET_assert (0 < success);
176   crc->rid = success;
177   GNUNET_SCHEDULER_add_continuation (&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              size_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   static int matched;
195   struct CpsRunContext *crc = cls;
196   int i;
197
198   if (key == NULL)
199     {
200       if (crc->i == 0)
201         {
202           crc->phase = RP_DEL;
203           crc->i = ITERATIONS;
204         }
205       GNUNET_assert (matched == GNUNET_YES);
206       matched = GNUNET_NO;
207       GNUNET_SCHEDULER_add_continuation (&run_continuation,
208                                          crc,
209                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
210       return;
211     }
212   i = crc->i;
213   GNUNET_assert (size == get_size (i));
214   GNUNET_assert (0 == memcmp (data, get_data(i), size));
215   GNUNET_assert (type == get_type (i));
216   GNUNET_assert (priority == get_priority (i));
217   GNUNET_assert (anonymity == get_anonymity(i));
218   GNUNET_assert (expiration.abs_value == get_expiration(i).abs_value);
219   matched = GNUNET_YES;
220   GNUNET_DATASTORE_iterate_get_next (datastore);
221 }
222
223
224 static void 
225 delete_value (void *cls,
226               const GNUNET_HashCode * key,
227               size_t size,
228               const void *data,
229               enum GNUNET_BLOCK_Type type,
230               uint32_t priority,
231               uint32_t anonymity,
232               struct GNUNET_TIME_Absolute
233               expiration, uint64_t uid)
234 {
235   struct CpsRunContext *crc = cls;
236   if (key == NULL)
237     {
238       if (crc->data == NULL)
239         {
240           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241                       "Content %u not found!\n",
242                       crc->i);
243           crc->phase = RP_ERROR;
244         }
245       else
246         {
247           crc->phase = RP_DO_DEL;
248         }
249       GNUNET_SCHEDULER_add_continuation (&run_continuation,
250                                          crc,
251                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
252       return;
253     }
254   GNUNET_assert (crc->data == NULL);
255   crc->size = size;
256   crc->key = *key;
257   crc->data = GNUNET_malloc (size);
258   memcpy (crc->data, data, size);
259   GNUNET_DATASTORE_iterate_get_next (datastore);
260 }
261
262
263 static void 
264 check_nothing (void *cls,
265                const GNUNET_HashCode * key,
266                size_t size,
267                const void *data,
268                enum GNUNET_BLOCK_Type type,
269                uint32_t priority,
270                uint32_t anonymity,
271                struct GNUNET_TIME_Absolute
272                expiration, uint64_t uid)
273 {
274   struct CpsRunContext *crc = cls;
275   GNUNET_assert (key == NULL);
276   if (crc->i == 0)
277     {
278       crc->phase = RP_RESERVE;    
279     }
280   GNUNET_SCHEDULER_add_continuation (&run_continuation,
281                                      crc,
282                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
283 }
284
285
286 static void 
287 check_multiple (void *cls,
288                 const GNUNET_HashCode * key,
289                 size_t size,
290                 const void *data,
291                 enum GNUNET_BLOCK_Type type,
292                 uint32_t priority,
293                 uint32_t anonymity,
294                 struct GNUNET_TIME_Absolute
295                 expiration, uint64_t uid)
296 {
297   struct CpsRunContext *crc = cls;
298
299   if (key == NULL)
300     {
301       if (crc->phase != RP_GET_MULTIPLE_DONE)
302         {
303           fprintf (stderr, 
304                    "Wrong phase: %d\n",
305                    crc->phase);
306           GNUNET_break (0);
307           crc->phase = RP_ERROR;
308         }
309       else
310         {
311           crc->phase = RP_UPDATE;
312         }
313       GNUNET_SCHEDULER_add_continuation (&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_iterate_get_next (datastore);
340 }
341
342
343 static void 
344 check_update (void *cls,
345               const GNUNET_HashCode * key,
346               size_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 (&run_continuation,
368                                          crc,
369                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
370       return;
371     }
372   if ( (anonymity == get_anonymity (42)) &&
373        (size == get_size (42)) &&
374        (priority == get_priority (42) + 100) )
375     {
376       crc->phase = RP_UPDATE_DONE;
377     }
378   else
379     GNUNET_assert (size == get_size (43));
380   GNUNET_DATASTORE_iterate_get_next (datastore);
381 }
382
383
384 static void
385 run_continuation (void *cls,
386                   const struct GNUNET_SCHEDULER_TaskContext *tc)
387 {
388   struct CpsRunContext *crc = cls;
389   ok = (int) crc->phase;
390 #if VERBOSE
391   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392               "Test in phase %u\n", crc->phase);
393 #endif
394   switch (crc->phase)
395     {
396     case RP_PUT:
397 #if VERBOSE
398       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399                   "Executing `%s' number %u\n",
400                   "PUT",
401                   crc->i);
402 #endif
403       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
404       GNUNET_DATASTORE_put (datastore,
405                             0,
406                             &crc->key,
407                             get_size (crc->i),
408                             get_data (crc->i),
409                             get_type (crc->i),
410                             get_priority (crc->i),
411                             get_anonymity (crc->i),
412                             0,
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_iterate_key (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_iterate_key (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_iterate_key (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                             0,
514                             get_expiration (42),
515                             1, 1, TIMEOUT,
516                             &check_success,
517                             crc);
518       break;
519     case RP_PUT_MULTIPLE_NEXT:
520       crc->phase = RP_GET_MULTIPLE;
521       GNUNET_DATASTORE_put (datastore,
522                             crc->rid,
523                             &crc->key,
524                             get_size (43),
525                             get_data (43),
526                             get_type (42),
527                             get_priority (43),
528                             get_anonymity (43),
529                             0,
530                             get_expiration (43),
531                             1, 1, TIMEOUT,
532                             &check_success,
533                             crc);
534       break;
535     case RP_GET_MULTIPLE:
536       GNUNET_DATASTORE_iterate_key (datastore,
537                                     &crc->key, 
538                                     get_type (42),
539                                     1, 1, TIMEOUT,
540                                     &check_multiple,
541                                     crc);
542       break;
543     case RP_GET_MULTIPLE_NEXT:
544     case RP_GET_MULTIPLE_DONE:
545       GNUNET_assert (0);
546       break;
547     case RP_UPDATE:
548       GNUNET_assert (crc->uid > 0);
549       crc->phase = RP_UPDATE_VALIDATE;
550       GNUNET_DATASTORE_update (datastore,
551                                crc->uid,
552                                100,
553                                get_expiration (42),
554                                1, 1, TIMEOUT,
555                                &check_success,
556                                crc);
557       break;
558     case RP_UPDATE_VALIDATE:
559       GNUNET_DATASTORE_iterate_key (datastore,
560                                     &crc->key, 
561                                     get_type (42),
562                                     1, 1, TIMEOUT,
563                                     &check_update,
564                                     crc);   
565       break;
566     case RP_UPDATE_DONE:
567       GNUNET_assert (0);
568       break;
569     case RP_DONE:
570 #if VERBOSE
571       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572                   "Finished, disconnecting\n");
573 #endif
574       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
575       GNUNET_free (crc);
576       ok = 0;
577       break;
578     case RP_ERROR:
579       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
580       GNUNET_free (crc);
581       ok = 43;
582       break;
583     }
584 }
585
586
587 static void
588 run_tests (void *cls,
589            int32_t success,
590            const char *msg)
591 {
592   struct CpsRunContext *crc = cls;
593
594   switch (success)
595     {
596     case GNUNET_YES:
597       GNUNET_SCHEDULER_add_continuation (&run_continuation,
598                                          crc,
599                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
600       return;
601     case GNUNET_NO:
602       fprintf (stderr,
603                "Test 'put' operation failed, key already exists (!?)\n");
604       GNUNET_free (crc);
605       return;
606     case GNUNET_SYSERR:
607       fprintf (stderr,
608                "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
609                msg);
610       GNUNET_free (crc);
611       return;
612     default:
613       GNUNET_assert (0);
614     }
615 }
616
617
618 static void
619 run (void *cls,
620      char *const *args,
621      const char *cfgfile,
622      const struct GNUNET_CONFIGURATION_Handle *cfg)
623 {
624   struct CpsRunContext *crc;
625   static GNUNET_HashCode zkey;
626
627   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
628   crc->cfg = cfg;
629   crc->phase = RP_PUT;
630   now = GNUNET_TIME_absolute_get ();
631   datastore = GNUNET_DATASTORE_connect (cfg);
632   if (NULL ==
633       GNUNET_DATASTORE_put (datastore, 0,
634                             &zkey, 4, "TEST",
635                             GNUNET_BLOCK_TYPE_TEST,
636                             0, 0, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS),
637                             0, 1, GNUNET_TIME_UNIT_MINUTES,
638                             &run_tests, crc))
639     {
640       fprintf (stderr,
641                "Test 'put' operation failed.\n");
642       ok = 1;
643       GNUNET_free (crc);
644     }
645 }
646
647
648 static int
649 check ()
650 {
651   char cfg_name[128];
652 #if START_DATASTORE
653   struct GNUNET_OS_Process *proc;
654 #endif
655   char *const argv[] = {
656     "test-datastore-api",
657     "-c",
658     cfg_name,
659 #if VERBOSE
660     "-L", "DEBUG",
661 #endif
662     NULL
663   };
664   struct GNUNET_GETOPT_CommandLineOption options[] = {
665     GNUNET_GETOPT_OPTION_END
666   };
667   GNUNET_snprintf (cfg_name,
668                    sizeof (cfg_name),
669                    "test_datastore_api_data_%s.conf",
670                    plugin_name);
671 #if START_DATASTORE
672   proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
673                                  "gnunet-service-arm",
674 #if VERBOSE
675                                  "-L", "DEBUG",
676 #endif
677                                  "-c", cfg_name, NULL);
678 #endif
679   GNUNET_assert (NULL != proc);
680   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
681                       argv, "test-datastore-api", "nohelp",
682                       options, &run, NULL);
683 #if START_DATASTORE
684   if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
685     {
686       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
687       ok = 1;
688     }
689   GNUNET_OS_process_wait (proc);
690   GNUNET_OS_process_close (proc);
691   proc = NULL;
692 #endif
693   if (ok != 0)
694     fprintf (stderr, "Missed some testcases: %u\n", ok);
695   return ok;
696 }
697
698 int
699 main (int argc, char *argv[])
700 {
701   int ret;
702   char *pos;
703   char dir_name[128];
704
705   /* determine name of plugin to use */
706   plugin_name = argv[0];
707   while (NULL != (pos = strstr(plugin_name, "_")))
708     plugin_name = pos+1;
709   if (NULL != (pos = strstr(plugin_name, ".")))
710     pos[0] = 0;
711   else
712     pos = (char *) plugin_name;
713
714   GNUNET_snprintf (dir_name,
715                    sizeof (dir_name),
716                    "/tmp/test-gnunet-datastore-%s",
717                    plugin_name);
718   GNUNET_DISK_directory_remove (dir_name);
719   GNUNET_log_setup ("test-datastore-api",
720 #if VERBOSE
721                     "DEBUG",
722 #else
723                     "WARNING",
724 #endif
725                     NULL);
726   ret = check ();
727   if (pos != plugin_name)
728     pos[0] = '.';
729   GNUNET_DISK_directory_remove (dir_name);
730   return ret;
731 }
732
733 /* end of test_datastore_api.c */