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