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