b2146a915066b6506fd22c539913de5f1162e277
[oweals/gnunet.git] / src / datastore / test_datastore_api_management.c
1 /*
2      This file is part of GNUnet.
3      (C) 2004, 2005, 2006, 2007, 2009, 2011 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 3, 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_management.c
22  * @brief Test for the space management functions of the datastore implementation.
23  * @author Christian Grothoff
24  */
25
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_datastore_service.h"
30
31 #define VERBOSE GNUNET_NO
32
33 /**
34  * How long until we give up on transmitting the message?
35  */
36 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
37
38 /**
39  * Number of iterations to run; must be large enough
40  * so that the quota will be exceeded!
41  */
42 #define ITERATIONS 5000
43
44 static struct GNUNET_DATASTORE_Handle *datastore;
45
46 static struct GNUNET_TIME_Absolute now;
47
48 static int ok;
49
50 static const char *plugin_name;
51
52 static size_t
53 get_size (int i)
54 {
55   return 8 + 8 * (i % 256);
56 }
57
58
59 static const void *
60 get_data (int i)
61 {
62   static char buf[60000];
63
64   memset (buf, i, 8 + 8 * (i % 256));
65   return buf;
66 }
67
68
69 static int
70 get_type (int i)
71 {
72   return 1;
73 }
74
75
76 static int
77 get_priority (int i)
78 {
79   return i + 1;
80 }
81
82
83 static int
84 get_anonymity (int i)
85 {
86   return i;
87 }
88
89
90 static struct GNUNET_TIME_Absolute
91 get_expiration (int i)
92 {
93   struct GNUNET_TIME_Absolute av;
94
95   av.abs_value = now.abs_value + i * 1000;
96   return av;
97 }
98
99 enum RunPhase
100 {
101   RP_PUT,
102   RP_GET,
103   RP_DONE,
104   RP_GET_FAIL
105 };
106
107
108 struct CpsRunContext
109 {
110   GNUNET_HashCode key;
111   int i;
112   int found;
113   const struct GNUNET_CONFIGURATION_Handle *cfg;
114   void *data;
115   enum RunPhase phase;
116   uint64_t offset;
117 };
118
119
120 static void
121 run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
122
123
124 static void
125 check_success (void *cls, int success, const char *msg)
126 {
127   struct CpsRunContext *crc = cls;
128
129   if (GNUNET_OK != success)
130     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", msg);
131   GNUNET_assert (GNUNET_OK == success);
132   GNUNET_free_non_null (crc->data);
133   crc->data = NULL;
134   GNUNET_SCHEDULER_add_continuation (&run_continuation,
135                                      crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
136 }
137
138
139 static void
140 check_value (void *cls,
141              const GNUNET_HashCode * key,
142              size_t size,
143              const void *data,
144              enum GNUNET_BLOCK_Type type,
145              uint32_t priority,
146              uint32_t anonymity,
147              struct GNUNET_TIME_Absolute expiration, uint64_t uid)
148 {
149   struct CpsRunContext *crc = cls;
150   int i;
151
152   if (NULL == key)
153   {
154     crc->phase = RP_GET_FAIL;
155     GNUNET_SCHEDULER_add_continuation (&run_continuation,
156                                        crc,
157                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
158     return;
159   }
160   i = crc->i;
161   GNUNET_assert (size == get_size (i));
162   GNUNET_assert (0 == memcmp (data, get_data (i), size));
163   GNUNET_assert (type == get_type (i));
164   GNUNET_assert (priority == get_priority (i));
165   GNUNET_assert (anonymity == get_anonymity (i));
166   GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value);
167   crc->offset++;
168   crc->i--;
169   if (crc->i == 0)
170     crc->phase = RP_DONE;
171   GNUNET_SCHEDULER_add_continuation (&run_continuation,
172                                      crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
173 }
174
175
176 static void
177 check_nothing (void *cls,
178                const GNUNET_HashCode * key,
179                size_t size,
180                const void *data,
181                enum GNUNET_BLOCK_Type type,
182                uint32_t priority,
183                uint32_t anonymity,
184                struct GNUNET_TIME_Absolute expiration, uint64_t uid)
185 {
186   struct CpsRunContext *crc = cls;
187
188   GNUNET_assert (key == NULL);
189   if (0 == --crc->i)
190     crc->phase = RP_DONE;
191   GNUNET_SCHEDULER_add_continuation (&run_continuation,
192                                      crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
193 }
194
195
196 static void
197 run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
198 {
199   struct CpsRunContext *crc = cls;
200
201   ok = (int) crc->phase;
202   switch (crc->phase)
203   {
204   case RP_PUT:
205 #if VERBOSE
206     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207                 "Executing `%s' number %u\n", "PUT", crc->i);
208 #endif
209     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
210     GNUNET_DATASTORE_put (datastore,
211                           0,
212                           &crc->key,
213                           get_size (crc->i),
214                           get_data (crc->i),
215                           get_type (crc->i),
216                           get_priority (crc->i),
217                           get_anonymity (crc->i),
218                           0,
219                           get_expiration (crc->i),
220                           1, 1, TIMEOUT, &check_success, crc);
221     crc->i++;
222     if (crc->i == ITERATIONS)
223     {
224       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
225                   "Sleeping to give datastore time to clean up\n");
226       sleep (1);
227       crc->phase = RP_GET;
228       crc->i--;
229     }
230     break;
231   case RP_GET:
232 #if VERBOSE
233     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234                 "Executing `%s' number %u\n", "GET", crc->i);
235 #endif
236     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
237     GNUNET_DATASTORE_get_key (datastore,
238                               crc->offset++,
239                               &crc->key,
240                               get_type (crc->i),
241                               1, 1, TIMEOUT, &check_value, crc);
242     break;
243   case RP_GET_FAIL:
244 #if VERBOSE
245     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
246                 "Executing `%s' number %u\n", "GET(f)", crc->i);
247 #endif
248     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
249     GNUNET_DATASTORE_get_key (datastore,
250                               crc->offset++,
251                               &crc->key,
252                               get_type (crc->i),
253                               1, 1, TIMEOUT, &check_nothing, crc);
254     break;
255   case RP_DONE:
256     GNUNET_assert (0 == crc->i);
257 #if VERBOSE
258     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n");
259 #endif
260     GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
261     GNUNET_free (crc);
262     ok = 0;
263   }
264 }
265
266
267 static void
268 run_tests (void *cls, int success, const char *msg)
269 {
270   struct CpsRunContext *crc = cls;
271
272   if (success != GNUNET_YES)
273   {
274     fprintf (stderr,
275              "Test 'put' operation failed with error `%s' database likely not setup, skipping test.",
276              msg);
277     GNUNET_free (crc);
278     return;
279   }
280   GNUNET_SCHEDULER_add_continuation (&run_continuation,
281                                      crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
282 }
283
284
285 static void
286 run (void *cls,
287      char *const *args,
288      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
289 {
290   struct CpsRunContext *crc;
291   static GNUNET_HashCode zkey;
292
293   crc = GNUNET_malloc (sizeof (struct CpsRunContext));
294   crc->cfg = cfg;
295   crc->phase = RP_PUT;
296   now = GNUNET_TIME_absolute_get ();
297   datastore = GNUNET_DATASTORE_connect (cfg);
298   if (NULL ==
299       GNUNET_DATASTORE_put (datastore, 0,
300                             &zkey, 4, "TEST",
301                             GNUNET_BLOCK_TYPE_TEST,
302                             0, 0, 0,
303                             GNUNET_TIME_relative_to_absolute
304                             (GNUNET_TIME_UNIT_SECONDS), 0, 1,
305                             GNUNET_TIME_UNIT_MINUTES, &run_tests, crc))
306   {
307     fprintf (stderr, "Test 'put' operation failed.\n");
308     GNUNET_free (crc);
309     ok = 1;
310   }
311 }
312
313
314
315 static int
316 check ()
317 {
318   struct GNUNET_OS_Process *proc;
319   char cfg_name[128];
320
321   char *const argv[] = {
322     "test-datastore-api-management",
323     "-c",
324     cfg_name,
325 #if VERBOSE
326     "-L", "DEBUG",
327 #endif
328     NULL
329   };
330   struct GNUNET_GETOPT_CommandLineOption options[] = {
331     GNUNET_GETOPT_OPTION_END
332   };
333   GNUNET_snprintf (cfg_name,
334                    sizeof (cfg_name),
335                    "test_datastore_api_data_%s.conf", plugin_name);
336   proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
337                                   "gnunet-service-arm",
338 #if VERBOSE
339                                   "-L", "DEBUG",
340 #endif
341                                   "-c", cfg_name, NULL);
342   GNUNET_assert (NULL != proc);
343   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
344                       argv, "test-datastore-api-management", "nohelp",
345                       options, &run, NULL);
346   sleep (1);                    /* give datastore chance to process 'DROP' request */
347   if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
348   {
349     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
350     ok = 1;
351   }
352   GNUNET_OS_process_wait (proc);
353   GNUNET_OS_process_close (proc);
354   proc = NULL;
355   if (ok != 0)
356     fprintf (stderr, "Missed some testcases: %u\n", ok);
357   return ok;
358 }
359
360 int
361 main (int argc, char *argv[])
362 {
363   int ret;
364
365   char *pos;
366   char dir_name[128];
367
368   sleep (1);
369   /* determine name of plugin to use */
370   plugin_name = argv[0];
371   while (NULL != (pos = strstr (plugin_name, "_")))
372     plugin_name = pos + 1;
373   if (NULL != (pos = strstr (plugin_name, ".")))
374     pos[0] = 0;
375   else
376     pos = (char *) plugin_name;
377
378   GNUNET_snprintf (dir_name,
379                    sizeof (dir_name),
380                    "/tmp/test-gnunet-datastore-%s", plugin_name);
381   GNUNET_DISK_directory_remove (dir_name);
382   GNUNET_log_setup ("test-datastore-api-management",
383 #if VERBOSE
384                     "DEBUG",
385 #else
386                     "WARNING",
387 #endif
388                     NULL);
389   ret = check ();
390   if (pos != plugin_name)
391     pos[0] = '.';
392   GNUNET_DISK_directory_remove (dir_name);
393   return ret;
394 }
395
396 /* end of test_datastore_api_management.c */