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