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