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