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