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