bugfixes
[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 datastore implementation.
23  * @author Christian Grothoff
24  *
25  * TODO:
26  * - test multiple values under same key
27  * - test "update"
28  * - test storage reservations
29  */
30
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_datastore_service.h"
35
36 #define VERBOSE GNUNET_NO
37
38 /**
39  * How long until we give up on transmitting the message?
40  */
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
42
43 #define ITERATIONS 256
44
45 static struct GNUNET_DATASTORE_Handle *datastore;
46
47 static struct GNUNET_TIME_Absolute now;
48
49 static int ok;
50
51
52 static size_t
53 get_size (int i)
54 {
55   return 8 * i;
56 }
57
58
59 static const void *
60 get_data (int i)
61 {
62   static char buf[60000]; 
63   memset (buf, i, 8 * i);
64   return buf;
65 }
66
67
68 static int
69 get_type(int i)
70 {
71   return i+1;
72 }
73
74
75 static int 
76 get_priority (int i)
77 {
78   return i+1;
79 }
80
81
82 static int
83 get_anonymity(int i)
84 {
85   return i;
86 }
87
88
89 static struct GNUNET_TIME_Absolute 
90 get_expiration (int i)
91 {
92   struct GNUNET_TIME_Absolute av;
93
94   av.value = now.value - i * 1000;
95   return av;
96 }
97
98 enum RunPhase
99   {
100     RP_DONE = 0,
101     RP_PUT,
102     RP_GET,
103     RP_DEL,
104     RP_DO_DEL,
105     RP_DELVALIDATE
106   };
107
108
109 struct CpsRunContext
110 {
111   GNUNET_HashCode key;
112   int i;
113   int *iptr;
114   struct GNUNET_SCHEDULER_Handle *sched;
115   struct GNUNET_CONFIGURATION_Handle *cfg;
116   void *data;
117   size_t size;
118   enum RunPhase phase;
119 };
120
121
122 static void
123 run_continuation (void *cls,
124                   const struct GNUNET_SCHEDULER_TaskContext *tc);
125
126
127 static void
128 check_success (void *cls,
129                int success,
130                const char *msg)
131 {
132   struct CpsRunContext *crc = cls;
133   if (GNUNET_OK != success)
134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
135                 "%s\n", msg);
136   GNUNET_assert (GNUNET_OK == success);
137   GNUNET_free_non_null (crc->data);
138   crc->data = NULL;
139   GNUNET_SCHEDULER_add_continuation (crc->sched,
140                                      GNUNET_NO,
141                                      &run_continuation,
142                                      crc,
143                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
144 }
145
146
147 static void 
148 check_value (void *cls,
149              const GNUNET_HashCode * key,
150              uint32_t size,
151              const void *data,
152              uint32_t type,
153              uint32_t priority,
154              uint32_t anonymity,
155              struct GNUNET_TIME_Absolute
156              expiration, uint64_t uid)
157 {
158   struct CpsRunContext *crc = cls;
159   int i;
160
161   if (key == NULL)
162     {
163       if (crc->i == 0)
164         {
165           crc->phase = RP_DEL;
166           crc->i = ITERATIONS;
167         }
168       GNUNET_SCHEDULER_add_continuation (crc->sched,
169                                          GNUNET_NO,
170                                          &run_continuation,
171                                          crc,
172                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
173       return;
174     }
175   i = crc->i;
176   GNUNET_assert (size == get_size (i));
177   GNUNET_assert (0 == memcmp (data, get_data(i), size));
178   GNUNET_assert (type == get_type (i));
179   GNUNET_assert (priority == get_priority (i));
180   GNUNET_assert (anonymity == get_anonymity(i));
181   GNUNET_assert (expiration.value == get_expiration(i).value);
182 }
183
184
185 static void 
186 delete_value (void *cls,
187              const GNUNET_HashCode * key,
188              uint32_t size,
189              const void *data,
190              uint32_t type,
191              uint32_t priority,
192              uint32_t anonymity,
193              struct GNUNET_TIME_Absolute
194              expiration, uint64_t uid)
195 {
196   struct CpsRunContext *crc = cls;
197   if (key == NULL)
198     {
199       crc->phase = RP_DO_DEL;
200       GNUNET_SCHEDULER_add_continuation (crc->sched,
201                                          GNUNET_NO,
202                                          &run_continuation,
203                                          crc,
204                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
205       return;
206     }
207   GNUNET_assert (crc->data == NULL);
208   crc->size = size;
209   crc->key = *key;
210   crc->data = GNUNET_malloc (size);
211   memcpy (crc->data, data, size);
212 }
213
214
215 static void 
216 check_nothing (void *cls,
217              const GNUNET_HashCode * key,
218              uint32_t size,
219              const void *data,
220              uint32_t 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   GNUNET_assert (key == NULL);
228   if (crc->i == 0)
229     {
230       crc->phase = RP_DONE;       
231     }
232   GNUNET_SCHEDULER_add_continuation (crc->sched,
233                                      GNUNET_NO,
234                                      &run_continuation,
235                                      crc,
236                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
237 }
238
239
240 static void
241 run_continuation (void *cls,
242                   const struct GNUNET_SCHEDULER_TaskContext *tc)
243 {
244   struct CpsRunContext *crc = cls;
245   ok = (int) crc->phase;
246   switch (crc->phase)
247     {
248     case RP_PUT:
249 #if VERBOSE
250       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251                   "Executing `%s' number %u\n",
252                   "PUT",
253                   crc->i);
254 #endif
255       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
256       GNUNET_DATASTORE_put (datastore,
257                             0,
258                             &crc->key,
259                             get_size (crc->i),
260                             get_data (crc->i),
261                             get_type (crc->i),
262                             get_priority (crc->i),
263                             get_anonymity (crc->i),
264                             get_expiration (crc->i),
265                             TIMEOUT,
266                             &check_success,
267                             crc);
268       crc->i++;
269       if (crc->i == ITERATIONS)
270         crc->phase = RP_GET;
271       break;
272     case RP_GET:
273       crc->i--;
274 #if VERBOSE
275       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
276                   "Executing `%s' number %u\n",
277                   "GET",
278                   crc->i);
279 #endif
280       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
281       GNUNET_DATASTORE_get (datastore, 
282                             &crc->key,
283                             get_type (crc->i),
284                             &check_value,
285                             crc,
286                             TIMEOUT);
287       break;
288     case RP_DEL:
289       crc->i--;
290 #if VERBOSE
291       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292                   "Executing `%s' number %u\n",
293                   "DEL",
294                   crc->i);
295 #endif
296       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
297       GNUNET_DATASTORE_get (datastore, 
298                             &crc->key,
299                             get_type (crc->i),
300                             &delete_value,
301                             crc,
302                             TIMEOUT);
303       break;
304     case RP_DO_DEL:
305 #if VERBOSE
306       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307                   "Executing `%s' number %u\n",
308                   "DO_DEL",
309                   crc->i);
310 #endif
311       if (crc->i == 0)
312         {
313           crc->i = ITERATIONS;   
314           crc->phase = RP_DELVALIDATE;
315         }      
316       else
317         {
318           crc->phase = RP_DEL;
319         }
320       GNUNET_DATASTORE_remove (datastore,
321                                &crc->key,
322                                crc->size,
323                                crc->data,
324                                &check_success,
325                                crc,
326                                TIMEOUT);
327       break;   
328     case RP_DELVALIDATE:
329       crc->i--;
330 #if VERBOSE
331       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332                   "Executing `%s' number %u\n",
333                   "DEL-VALIDATE",
334                   crc->i);
335 #endif
336       GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
337       GNUNET_DATASTORE_get (datastore, 
338                             &crc->key,
339                             get_type (crc->i),
340                             &check_nothing,
341                             crc,
342                             TIMEOUT);
343       break;
344   /* check reservations */
345   /* check update */
346   /* test multiple results */
347     case RP_DONE:
348 #if VERBOSE
349       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
350                   "Finished, disconnecting\n");
351 #endif
352       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
353       ok = 0;
354     }
355 }
356
357
358 static void
359 run (void *cls,
360      struct GNUNET_SCHEDULER_Handle *sched,
361      char *const *args,
362      const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg)
363 {
364   struct CpsRunContext *crc;
365
366   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
367   crc->sched = sched;
368   crc->cfg = cfg;
369   crc->phase = RP_PUT;
370   now.value = 1000000;
371   datastore = GNUNET_DATASTORE_connect (cfg, sched);
372   GNUNET_SCHEDULER_add_continuation (crc->sched,
373                                      GNUNET_NO,
374                                      &run_continuation,
375                                      crc,
376                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
377
378 }
379
380
381
382 static int
383 check ()
384 {
385   pid_t pid;
386   char *const argv[] = { "test-datastore-api",
387     "-c",
388     "test_datastore_api_data.conf",
389 #if VERBOSE
390     "-L", "DEBUG",
391 #endif
392     NULL
393   };
394   struct GNUNET_GETOPT_CommandLineOption options[] = {
395     GNUNET_GETOPT_OPTION_END
396   };
397   pid = GNUNET_OS_start_process ("gnunet-service-datastore",
398                                  "gnunet-service-datastore",
399 #if VERBOSE
400                                  "-L", "DEBUG",
401 #endif
402                                  "-c", "test_datastore_api_data.conf", NULL);
403   sleep (1);
404   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
405                       argv, "test-datastore-api", "nohelp",
406                       options, &run, NULL);
407   if (0 != PLIBC_KILL (pid, SIGTERM))
408     {
409       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
410       ok = 1;
411     }
412   GNUNET_OS_process_wait(pid);
413   if (ok != 0)
414     fprintf (stderr, "Missed some testcases: %u\n", ok);
415   return ok;
416 }
417
418 int
419 main (int argc, char *argv[])
420 {
421   int ret;
422   
423   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-datastore");
424   GNUNET_log_setup ("test-datastore-api",
425 #if VERBOSE
426                     "DEBUG",
427 #else
428                     "WARNING",
429 #endif
430                     NULL);
431   ret = check ();
432
433   return ret;
434 }
435
436
437
438 /* end of test_datastore_api.c */