afc36b7089e645f44c8be72dc9a0180ff7159ee7
[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 /**
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 static struct GNUNET_DATASTORE_Handle *datastore;
42
43 static struct GNUNET_TIME_Absolute now;
44
45 static int ok;
46
47
48 static size_t
49 get_size (int i)
50 {
51   return 8 * i;
52 }
53
54
55 static const void *
56 get_data (int i)
57 {
58   static char buf[60000]; 
59   memset (buf, i, 8 * i);
60   return buf;
61 }
62
63
64 static int
65 get_type(int i)
66 {
67   return i;
68 }
69
70
71 static int 
72 get_priority (int i)
73 {
74   return i+1;
75 }
76
77
78 static int
79 get_anonymity(int i)
80 {
81   return i;
82 }
83
84
85 static struct GNUNET_TIME_Absolute 
86 get_expiration (int i)
87 {
88   struct GNUNET_TIME_Absolute av;
89
90   av.value = now.value - i * 1000;
91   return av;
92 }
93
94 enum RunPhase
95   {
96     RP_DONE = 0,
97     RP_PUT,
98     RP_GET,
99     RP_DEL,
100     RP_DELVALIDATE
101   };
102
103
104 struct CpsRunContext
105 {
106   GNUNET_HashCode key;
107   int i;
108   int *iptr;
109   struct GNUNET_SCHEDULER_Handle *sched;
110   struct GNUNET_CONFIGURATION_Handle *cfg;
111   enum RunPhase phase;
112 };
113
114
115 static void
116 run_continuation (void *cls,
117                   const struct GNUNET_SCHEDULER_TaskContext *tc);
118
119
120 static void
121 check_success (void *cls,
122                int success,
123                const char *msg)
124 {
125   struct CpsRunContext *crc = cls;
126   if (GNUNET_OK != success)
127     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
128                 "%s\n", msg);
129   GNUNET_assert (GNUNET_OK == success);
130   GNUNET_SCHEDULER_add_continuation (crc->sched,
131                                      GNUNET_NO,
132                                      &run_continuation,
133                                      crc,
134                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
135 }
136
137
138 static void
139 check_failure (void *cls,
140                int success,
141                const char *msg)
142 {
143   struct CpsRunContext *crc = cls;
144   GNUNET_assert (GNUNET_OK != success);
145   GNUNET_assert (NULL != msg);
146   GNUNET_SCHEDULER_add_continuation (crc->sched,
147                                      GNUNET_NO,
148                                      &run_continuation,
149                                      crc,
150                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
151 }
152
153
154 static void 
155 check_value (void *cls,
156              const GNUNET_HashCode * key,
157              uint32_t size,
158              const void *data,
159              uint32_t type,
160              uint32_t priority,
161              uint32_t anonymity,
162              struct GNUNET_TIME_Absolute
163              expiration, uint64_t uid)
164 {
165   struct CpsRunContext *crc = cls;
166   int i;
167
168   if (key == NULL)
169     return;
170   i = crc->i;
171   GNUNET_assert (size == get_size (i));
172   GNUNET_assert (0 == memcmp (data, get_data(i), size));
173   GNUNET_assert (type == get_type (i));
174   GNUNET_assert (priority == get_priority (i));
175   GNUNET_assert (anonymity == get_anonymity(i));
176   GNUNET_assert (expiration.value == get_expiration(i).value);
177   GNUNET_SCHEDULER_add_continuation (crc->sched,
178                                      GNUNET_NO,
179                                      &run_continuation,
180                                      crc,
181                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
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     return;
199   GNUNET_DATASTORE_remove (datastore,
200                            key,
201                            size,
202                            data,
203                            &check_success,
204                            NULL,
205                            TIMEOUT);
206   ((int*)key)[0]++;
207   GNUNET_DATASTORE_remove (datastore,
208                            key,
209                            size,
210                            data,
211                            &check_failure,
212                            NULL,
213                            TIMEOUT);
214   GNUNET_SCHEDULER_add_continuation (crc->sched,
215                                      GNUNET_NO,
216                                      &run_continuation,
217                                      crc,
218                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
219 }
220
221
222
223 static void 
224 check_nothing (void *cls,
225              const GNUNET_HashCode * key,
226              uint32_t size,
227              const void *data,
228              uint32_t type,
229              uint32_t priority,
230              uint32_t anonymity,
231              struct GNUNET_TIME_Absolute
232              expiration, uint64_t uid)
233 {
234   struct CpsRunContext *crc = cls;
235   GNUNET_assert (key == NULL);
236   GNUNET_SCHEDULER_add_continuation (crc->sched,
237                                      GNUNET_NO,
238                                      &run_continuation,
239                                      crc,
240                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
241 }
242
243
244 static void
245 run_continuation (void *cls,
246                   const struct GNUNET_SCHEDULER_TaskContext *tc)
247 {
248   struct CpsRunContext *crc = cls;
249   ok = (int) crc->phase;
250   switch (crc->phase)
251     {
252     case RP_PUT:
253       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
254       GNUNET_DATASTORE_put (datastore,
255                             0,
256                             &crc->key,
257                             get_size (crc->i),
258                             get_data (crc->i),
259                             get_type (crc->i),
260                             get_priority (crc->i),
261                             get_anonymity (crc->i),
262                             get_expiration (crc->i),
263                             TIMEOUT,
264                             &check_success,
265                             crc);
266       crc->i++;
267       if (crc->i == 256)
268         crc->phase = RP_GET;
269       break;
270     case RP_GET:
271       crc->i--;
272       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
273       GNUNET_DATASTORE_get (datastore, 
274                             &crc->key,
275                             get_type (crc->i),
276                             &check_value,
277                             crc,
278                             TIMEOUT);
279       if (crc->i == 0)
280         {
281           crc->phase = RP_DEL;
282           crc->i = 256;
283         }
284       break;
285     case RP_DEL:
286       crc->i--;
287       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
288       GNUNET_DATASTORE_get (datastore, 
289                             &crc->key,
290                             get_type (crc->i),
291                             &delete_value,
292                             crc,
293                             TIMEOUT);
294       if (crc->i == 0)
295         {
296           crc->phase = RP_DELVALIDATE;
297           crc->i = 256;  
298         }
299       break;
300     case RP_DELVALIDATE:
301       crc->i--;
302       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
303       GNUNET_DATASTORE_get (datastore, 
304                             &crc->key,
305                             get_type (crc->i),
306                             &check_nothing,
307                             crc,
308                             TIMEOUT);
309       if (crc->i == 0)
310         {
311           crc->phase = RP_DONE;   
312         }
313       break;
314   /* check reservations */
315   /* check update */
316   /* test multiple results */
317     case RP_DONE:
318       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
319       ok = 0;
320     }
321 }
322
323
324 static void
325 run (void *cls,
326      struct GNUNET_SCHEDULER_Handle *sched,
327      char *const *args,
328      const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg)
329 {
330   struct CpsRunContext *crc;
331
332   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
333   crc->sched = sched;
334   crc->cfg = cfg;
335   crc->phase = RP_PUT;
336   now.value = 1000000;
337   datastore = GNUNET_DATASTORE_connect (cfg, sched);
338   GNUNET_SCHEDULER_add_continuation (crc->sched,
339                                      GNUNET_NO,
340                                      &run_continuation,
341                                      crc,
342                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
343
344 }
345
346
347
348 static int
349 check ()
350 {
351   pid_t pid;
352   char *const argv[] = { "test-datastore-api",
353     "-c",
354     "test_datastore_api_data.conf",
355 #if VERBOSE
356     "-L", "DEBUG",
357 #endif
358     NULL
359   };
360   struct GNUNET_GETOPT_CommandLineOption options[] = {
361     GNUNET_GETOPT_OPTION_END
362   };
363   pid = GNUNET_OS_start_process ("gnunet-service-datastore",
364                                  "gnunet-service-datastore",
365 #if VERBOSE
366                                  "-L", "DEBUG",
367 #endif
368                                  "-c", "test_datastore_api_data.conf", NULL);
369   sleep (1);
370   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
371                       argv, "test-datastore-api", "nohelp",
372                       options, &run, NULL);
373   if (0 != PLIBC_KILL (pid, SIGTERM))
374     {
375       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
376       ok = 1;
377     }
378   GNUNET_OS_process_wait(pid);
379   if (ok != 0)
380     fprintf (stderr, "Missed some testcases: %u\n", ok);
381   return ok;
382 }
383
384 int
385 main (int argc, char *argv[])
386 {
387   int ret;
388
389   GNUNET_log_setup ("test-datastore-api",
390 #if VERBOSE
391                     "DEBUG",
392 #else
393                     "WARNING",
394 #endif
395                     NULL);
396   ret = check ();
397
398   return ret;
399 }
400
401
402
403 /* end of test_datastore_api.c */