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