353050a53a8d7845ccc2b584b0054099de5a487d
[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 tatic 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   ((int*)key)[0]++;
206   GNUNET_DATASTORE_remove (datastore,
207                            key,
208                            size,
209                            data,
210                            &check_failure,
211                            NULL);
212   GNUNET_SCHEDULER_add_continuation (crc->sched,
213                                      GNUNET_NO,
214                                      &run_continuation,
215                                      crc,
216                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
217 }
218
219
220
221 static void 
222 check_nothing (void *cls,
223              const GNUNET_HashCode * key,
224              uint32_t size,
225              const void *data,
226              uint32_t type,
227              uint32_t priority,
228              uint32_t anonymity,
229              struct GNUNET_TIME_Absolute
230              expiration, uint64_t uid)
231 {
232   struct CpsRunContext *crc = cls;
233   GNUNET_assert (key == NULL);
234   GNUNET_SCHEDULER_add_continuation (crc->sched,
235                                      GNUNET_NO,
236                                      &run_continuation,
237                                      crc,
238                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
239 }
240
241
242 static void
243 run_continuation (void *cls,
244                   const struct GNUNET_SCHEDULER_TaskContext *tc)
245 {
246   struct CpsRunContext *crc = cls;
247   ok = (int) crc->phase;
248   switch (crc->phase)
249     {
250     case RP_PUT:
251       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
252       GNUNET_DATASTORE_put (datastore,
253                             0,
254                             &crc->key,
255                             get_size (crc->i),
256                             get_data (crc->i),
257                             get_type (crc->i),
258                             get_priority (crc->i),
259                             get_anonymity (crc->i),
260                             get_expiration (crc->i),
261                             TIMEOUT,
262                             &check_success,
263                             crc);
264       crc->i++;
265       if (crc->i == 256)
266         crc->phase = RP_GET;
267       break;
268     case RP_GET:
269       crc->i--;
270       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
271       GNUNET_DATASTORE_get (datastore, 
272                             &crc->key,
273                             get_type (crc->i),
274                             &check_value,
275                             crc);
276       if (crc->i == 0)
277         {
278           crc->phase = RP_DEL;
279           crc->i = 256;
280         }
281       break;
282     case RP_DEL:
283       crc->i--;
284       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
285       GNUNET_DATASTORE_get (datastore, 
286                             &crc->key,
287                             get_type (crc->i),
288                             &delete_value,
289                             crc);
290       if (crc->i == 0)
291         {
292           crc->phase = RP_DELVALIDATE;
293           crc->i = 256;  
294         }
295       break;
296     case RP_DELVALIDATE:
297       crc->i--;
298       memset (&crc->key, 256 - crc->i, sizeof (GNUNET_HashCode));
299       GNUNET_DATASTORE_get (datastore, 
300                             &crc->key,
301                             get_type (crc->i),
302                             &check_nothing,
303                             crc);
304       if (crc->i == 0)
305         {
306           crc->phase = RP_DONE;   
307         }
308       break;
309   /* check reservations */
310   /* check update */
311   /* test multiple results */
312     case RP_DONE:
313       GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
314       ok = 0;
315     }
316 }
317
318
319 static void
320 run (void *cls,
321      struct GNUNET_SCHEDULER_Handle *sched,
322      char *const *args,
323      const char *cfgfile, struct GNUNET_CONFIGURATION_Handle *cfg)
324 {
325   struct CpsRunContext *crc;
326
327   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
328   crc->sched = sched;
329   crc->cfg = cfg;
330   crc->phase = RP_PUT;
331   now.value = 1000000;
332   datastore = GNUNET_DATASTORE_connect (cfg, sched);
333   GNUNET_SCHEDULER_add_continuation (crc->sched,
334                                      GNUNET_NO,
335                                      &run_continuation,
336                                      crc,
337                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
338
339 }
340
341
342
343 static int
344 check ()
345 {
346   pid_t pid;
347   char *const argv[] = { "test-datastore-api",
348     "-c",
349     "test_datastore_api_data.conf",
350 #if VERBOSE
351     "-L", "DEBUG",
352 #endif
353     NULL
354   };
355   struct GNUNET_GETOPT_CommandLineOption options[] = {
356     GNUNET_GETOPT_OPTION_END
357   };
358   pid = GNUNET_OS_start_process ("gnunet-service-datastore",
359                                  "gnunet-service-datastore",
360 #if VERBOSE
361                                  "-L", "DEBUG",
362 #endif
363                                  "-c", "test_datastore_api_data.conf", NULL);
364   sleep (1);
365   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
366                       argv, "test-datastore-api", "nohelp",
367                       options, &run, NULL);
368   if (0 != PLIBC_KILL (pid, SIGTERM))
369     {
370       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
371       ok = 1;
372     }
373   GNUNET_OS_process_wait(pid);
374   if (ok != 0)
375     fprintf (stderr, "Missed some testcases: %u\n", ok);
376   return ok;
377 }
378
379 int
380 main (int argc, char *argv[])
381 {
382   int ret;
383
384   GNUNET_log_setup ("test-datastore-api",
385 #if VERBOSE
386                     "DEBUG",
387 #else
388                     "WARNING",
389 #endif
390                     NULL);
391   ret = check ();
392
393   return ret;
394 }
395
396
397
398 /* end of test_datastore_api.c */