continue to fix extract result
[oweals/gnunet.git] / src / datastore / test_datastore_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2004, 2005, 2006, 2007, 2009, 2015 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 #include "gnunet_testing_lib.h"
34
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 /**
44  * Handle to the datastore.
45  */
46 static struct GNUNET_DATASTORE_Handle *datastore;
47
48 static struct GNUNET_TIME_Absolute now;
49
50 /**
51  * Value we return from #main().
52  */
53 static int ok;
54
55 /**
56  * Name of plugin under test.
57  */
58 static const char *plugin_name;
59
60
61 static size_t
62 get_size (int i)
63 {
64   return 8 * i;
65 }
66
67
68 static const void *
69 get_data (int i)
70 {
71   static char buf[60000];
72
73   memset (buf, i, 8 * i);
74   return buf;
75 }
76
77
78 static int
79 get_type (int i)
80 {
81   return i + 1;
82 }
83
84
85 static int
86 get_priority (int i)
87 {
88   return i + 1;
89 }
90
91
92 static int
93 get_anonymity (int i)
94 {
95   return i;
96 }
97
98
99 static struct GNUNET_TIME_Absolute
100 get_expiration (int i)
101 {
102   struct GNUNET_TIME_Absolute av;
103
104   av.abs_value_us = now.abs_value_us + 20000000000LL - i * 1000 * 1000LL;
105   return av;
106 }
107
108
109 /**
110  * Which phase of the process are we in?
111  */
112 enum RunPhase
113 {
114   /**
115    * We are done (shutting down normally).
116    */
117   RP_DONE = 0,
118
119   /**
120    * We are adding new entries to the datastore.
121    */
122   RP_PUT = 1,
123   RP_GET = 2,
124   RP_DEL = 3,
125   RP_DO_DEL = 4,
126   RP_DELVALIDATE = 5,
127   RP_RESERVE = 6,
128   RP_PUT_MULTIPLE = 7,
129   RP_PUT_MULTIPLE_NEXT = 8,
130   RP_GET_MULTIPLE = 9,
131   RP_GET_MULTIPLE_NEXT = 10,
132   RP_UPDATE = 11,
133   RP_UPDATE_VALIDATE = 12,
134
135   /**
136    * Execution failed with some kind of error.
137    */
138   RP_ERROR
139 };
140
141
142 /**
143  * Closure we give to all of the functions executing the
144  * benchmark.  Could right now be global, but this allows
145  * us to theoretically run multiple clients "in parallel".
146  */
147 struct CpsRunContext
148 {
149   /**
150    * Execution phase we are in.
151    */
152   enum RunPhase phase;
153
154   struct GNUNET_HashCode key;
155   int i;
156   int rid;
157   void *data;
158   size_t size;
159
160   uint64_t uid;
161   uint64_t offset;
162   uint64_t first_uid;
163 };
164
165
166 /**
167  * Main state machine.  Executes the next step of the test
168  * depending on the current state.
169  *
170  * @param cls the `struct CpsRunContext`
171  */
172 static void
173 run_continuation (void *cls);
174
175
176 /**
177  * Continuation called to notify client about result of an
178  * operation.  Checks for errors, updates our iteration counters and
179  * continues execution with #run_continuation().
180  *
181  * @param cls the `struct CpsRunContext`
182  * @param success #GNUNET_SYSERR on failure
183  * @param min_expiration minimum expiration time required for content to be stored
184  *                by the datacache at this time, zero for unknown
185  * @param msg NULL on success, otherwise an error message
186  */
187 static void
188 check_success (void *cls,
189                int success,
190                struct GNUNET_TIME_Absolute min_expiration,
191                const char *msg)
192 {
193   struct CpsRunContext *crc = cls;
194
195   if (GNUNET_OK != success)
196   {
197     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198                 "Operation %d/%d not successful: `%s'\n",
199                 crc->phase,
200                 crc->i,
201                 msg);
202     crc->phase = RP_ERROR;
203   }
204   GNUNET_free_non_null (crc->data);
205   crc->data = NULL;
206   GNUNET_SCHEDULER_add_now (&run_continuation, crc);
207 }
208
209
210 static void
211 get_reserved (void *cls,
212               int success,
213               struct GNUNET_TIME_Absolute min_expiration,
214               const char *msg)
215 {
216   struct CpsRunContext *crc = cls;
217
218   if (0 >= success)
219     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
220                 "Error obtaining reservation: `%s'\n",
221                 msg);
222   GNUNET_assert (0 < success);
223   crc->rid = success;
224   GNUNET_SCHEDULER_add_now (&run_continuation,
225                             crc);
226 }
227
228
229 static void
230 check_value (void *cls,
231              const struct GNUNET_HashCode *key,
232              size_t size,
233              const void *data,
234              enum GNUNET_BLOCK_Type type,
235              uint32_t priority,
236              uint32_t anonymity,
237              struct GNUNET_TIME_Absolute expiration,
238              uint64_t uid)
239 {
240   struct CpsRunContext *crc = cls;
241   int i;
242
243   i = crc->i;
244   if (NULL == key)
245   {
246     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247                 "Value check failed (got NULL key) in %d/%d\n",
248                 crc->phase,
249                 crc->i);
250     crc->phase = RP_ERROR;
251     GNUNET_SCHEDULER_add_now (&run_continuation,
252                               crc);
253     return;
254   }
255 #if 0
256   FPRINTF (stderr,
257            "Check value got `%s' of size %u, type %d, expire %s\n",
258            GNUNET_h2s (key), (unsigned int) size, type,
259            GNUNET_STRINGS_absolute_time_to_string (expiration));
260   FPRINTF (stderr,
261            "Check value iteration %d wants size %u, type %d, expire %s\n", i,
262            (unsigned int) get_size (i), get_type (i),
263            GNUNET_STRINGS_absolute_time_to_string (get_expiration(i)));
264 #endif
265   GNUNET_assert (size == get_size (i));
266   GNUNET_assert (0 == memcmp (data, get_data (i), size));
267   GNUNET_assert (type == get_type (i));
268   GNUNET_assert (priority == get_priority (i));
269   GNUNET_assert (anonymity == get_anonymity (i));
270   GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
271   crc->offset++;
272   if (crc->i == 0)
273   {
274     crc->phase = RP_DEL;
275     crc->i = ITERATIONS;
276   }
277   GNUNET_SCHEDULER_add_now (&run_continuation,
278                             crc);
279 }
280
281
282 static void
283 delete_value (void *cls,
284               const struct GNUNET_HashCode *key,
285               size_t size,
286               const void *data,
287               enum GNUNET_BLOCK_Type type,
288               uint32_t priority,
289               uint32_t anonymity,
290               struct GNUNET_TIME_Absolute expiration,
291               uint64_t uid)
292 {
293   struct CpsRunContext *crc = cls;
294
295   GNUNET_assert (NULL == crc->data);
296   GNUNET_assert (NULL != key);
297   crc->size = size;
298   crc->key = *key;
299   crc->data = GNUNET_malloc (size);
300   memcpy (crc->data, data, size);
301   crc->phase = RP_DO_DEL;
302   GNUNET_SCHEDULER_add_now (&run_continuation,
303                             crc);
304 }
305
306
307 static void
308 check_nothing (void *cls,
309                const struct GNUNET_HashCode *key,
310                size_t size,
311                const void *data,
312                enum GNUNET_BLOCK_Type type,
313                uint32_t priority,
314                uint32_t anonymity,
315                struct GNUNET_TIME_Absolute expiration,
316                uint64_t uid)
317 {
318   struct CpsRunContext *crc = cls;
319
320   GNUNET_assert (key == NULL);
321   if (crc->i == 0)
322     crc->phase = RP_RESERVE;
323   GNUNET_SCHEDULER_add_now (&run_continuation,
324                             crc);
325 }
326
327
328 static void
329 check_multiple (void *cls,
330                 const struct GNUNET_HashCode *key,
331                 size_t size,
332                 const void *data,
333                 enum GNUNET_BLOCK_Type type,
334                 uint32_t priority,
335                 uint32_t anonymity,
336                 struct GNUNET_TIME_Absolute expiration,
337                 uint64_t uid)
338 {
339   struct CpsRunContext *crc = cls;
340
341   GNUNET_assert (key != NULL);
342   switch (crc->phase)
343   {
344   case RP_GET_MULTIPLE:
345     crc->phase = RP_GET_MULTIPLE_NEXT;
346     crc->first_uid = uid;
347     crc->offset++;
348     break;
349   case RP_GET_MULTIPLE_NEXT:
350     GNUNET_assert (uid != crc->first_uid);
351     crc->phase = RP_UPDATE;
352     break;
353   default:
354     GNUNET_break (0);
355     crc->phase = RP_ERROR;
356     break;
357   }
358   if (priority == get_priority (42))
359     crc->uid = uid;
360   GNUNET_SCHEDULER_add_now (&run_continuation, crc);
361 }
362
363
364 static void
365 check_update (void *cls,
366               const struct GNUNET_HashCode *key,
367               size_t size,
368               const void *data,
369               enum GNUNET_BLOCK_Type type,
370               uint32_t priority,
371               uint32_t anonymity,
372               struct GNUNET_TIME_Absolute expiration,
373               uint64_t uid)
374 {
375   struct CpsRunContext *crc = cls;
376
377   GNUNET_assert (key != NULL);
378   if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
379       (priority == get_priority (42) + 100))
380     crc->phase = RP_DONE;
381   else
382   {
383     GNUNET_assert (size == get_size (43));
384     crc->offset++;
385   }
386   GNUNET_SCHEDULER_add_now (&run_continuation, crc);
387 }
388
389
390 /**
391  * Main state machine.  Executes the next step of the test
392  * depending on the current state.
393  *
394  * @param cls the `struct CpsRunContext`
395  */
396 static void
397 run_continuation (void *cls)
398 {
399   struct CpsRunContext *crc = cls;
400
401   ok = (int) crc->phase;
402   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403               "Test in phase %u\n",
404               crc->phase);
405   switch (crc->phase)
406   {
407   case RP_PUT:
408     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409                 "Executing PUT number %u\n",
410                 crc->i);
411     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
412     GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
413                           get_data (crc->i), get_type (crc->i),
414                           get_priority (crc->i), get_anonymity (crc->i), 0,
415                           get_expiration (crc->i), 1, 1, TIMEOUT,
416                           &check_success, crc);
417     crc->i++;
418     if (crc->i == ITERATIONS)
419       crc->phase = RP_GET;
420     break;
421   case RP_GET:
422     crc->i--;
423     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424                 "Executing GET number %u\n",
425                 crc->i);
426     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
427     GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
428                               get_type (crc->i), 1, 1, TIMEOUT,
429                               &check_value, crc);
430     break;
431   case RP_DEL:
432     crc->i--;
433     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434                 "Executing DEL number %u\n",
435                 crc->i);
436     crc->data = NULL;
437     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
438     GNUNET_assert (NULL !=
439                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
440                                              get_type (crc->i), 1, 1, TIMEOUT,
441                                              &delete_value, crc));
442     break;
443   case RP_DO_DEL:
444     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445                 "Executing DO_DEL number %u\n",
446                 crc->i);
447     if (crc->i == 0)
448     {
449       crc->i = ITERATIONS;
450       crc->phase = RP_DELVALIDATE;
451     }
452     else
453     {
454       crc->phase = RP_DEL;
455     }
456     GNUNET_assert (NULL !=
457                    GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
458                                             crc->data, 1, 1, TIMEOUT,
459                                             &check_success, crc));
460     break;
461   case RP_DELVALIDATE:
462     crc->i--;
463     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464                 "Executing DELVALIDATE number %u\n",
465                 crc->i);
466     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
467     GNUNET_assert (NULL !=
468                    GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
469                                              get_type (crc->i), 1, 1, TIMEOUT,
470                                              &check_nothing, crc));
471     break;
472   case RP_RESERVE:
473     crc->phase = RP_PUT_MULTIPLE;
474     GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2,
475                               &get_reserved, crc);
476     break;
477   case RP_PUT_MULTIPLE:
478     crc->phase = RP_PUT_MULTIPLE_NEXT;
479     GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
480                           get_data (42), get_type (42), get_priority (42),
481                           get_anonymity (42), 0, get_expiration (42), 1, 1,
482                           TIMEOUT, &check_success, crc);
483     break;
484   case RP_PUT_MULTIPLE_NEXT:
485     crc->phase = RP_GET_MULTIPLE;
486     GNUNET_DATASTORE_put (datastore, crc->rid,
487                           &crc->key,
488                           get_size (43),
489                           get_data (43),
490                           get_type (42),
491                           get_priority (43),
492                           get_anonymity (43),
493                           0,
494                           get_expiration (43),
495                           1, 1,
496                           TIMEOUT,
497                           &check_success, crc);
498     break;
499   case RP_GET_MULTIPLE:
500     GNUNET_assert (NULL !=
501                    GNUNET_DATASTORE_get_key (datastore,
502                                              crc->offset,
503                                              &crc->key,
504                                              get_type (42), 1, 1,
505                                              TIMEOUT,
506                                              &check_multiple, crc));
507     break;
508   case RP_GET_MULTIPLE_NEXT:
509     GNUNET_assert (NULL !=
510                    GNUNET_DATASTORE_get_key (datastore,
511                                              crc->offset,
512                                              &crc->key,
513                                              get_type (42),
514                                              1, 1,
515                                              TIMEOUT,
516                                              &check_multiple, crc));
517     break;
518   case RP_UPDATE:
519     GNUNET_assert (crc->uid > 0);
520     crc->phase = RP_UPDATE_VALIDATE;
521     GNUNET_DATASTORE_update (datastore,
522                              crc->uid, 100,
523                              get_expiration (42), 1,
524                              1, TIMEOUT,
525                              &check_success, crc);
526     break;
527   case RP_UPDATE_VALIDATE:
528     GNUNET_assert (NULL !=
529                    GNUNET_DATASTORE_get_key (datastore,
530                                              crc->offset,
531                                              &crc->key,
532                                              get_type (42),
533                                              1, 1,
534                                              TIMEOUT,
535                                              &check_update, crc));
536     break;
537   case RP_DONE:
538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                 "Finished, disconnecting\n");
540     GNUNET_DATASTORE_disconnect (datastore,
541                                  GNUNET_YES);
542     GNUNET_free (crc);
543     ok = 0;
544     break;
545   case RP_ERROR:
546     GNUNET_DATASTORE_disconnect (datastore,
547                                  GNUNET_YES);
548     GNUNET_free (crc);
549     ok = 43;
550     break;
551   }
552 }
553
554
555 /**
556  * Function called with the result of the initial PUT operation.  If
557  * the PUT succeeded, we start the actual benchmark loop, otherwise we
558  * bail out with an error.
559  *
560  *
561  * @param cls closure
562  * @param success #GNUNET_SYSERR on failure
563  * @param min_expiration minimum expiration time required for content to be stored
564  *                by the datacache at this time, zero for unknown
565  * @param msg NULL on success, otherwise an error message
566  */
567 static void
568 run_tests (void *cls,
569            int32_t success,
570            struct GNUNET_TIME_Absolute min_expiration,
571            const char *msg)
572 {
573   struct CpsRunContext *crc = cls;
574
575   switch (success)
576   {
577   case GNUNET_YES:
578     GNUNET_SCHEDULER_add_now (&run_continuation,
579                               crc);
580     return;
581   case GNUNET_NO:
582     FPRINTF (stderr,
583              "%s", "Test 'put' operation failed, key already exists (!?)\n");
584     GNUNET_DATASTORE_disconnect (datastore,
585                                  GNUNET_YES);
586     GNUNET_free (crc);
587     return;
588   case GNUNET_SYSERR:
589     FPRINTF (stderr,
590              "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
591              msg);
592     GNUNET_DATASTORE_disconnect (datastore,
593                                  GNUNET_YES);
594     GNUNET_free (crc);
595     return;
596   default:
597     GNUNET_assert (0);
598   }
599 }
600
601
602 /**
603  * Beginning of the actual execution of the benchmark.
604  * Performs a first test operation (PUT) to verify that
605  * the plugin works at all.
606  *
607  * @param cls NULL
608  * @param cfg configuration to use
609  * @param peer peer handle (unused)
610  */
611 static void
612 run (void *cls,
613      const struct GNUNET_CONFIGURATION_Handle *cfg,
614      struct GNUNET_TESTING_Peer *peer)
615 {
616   struct CpsRunContext *crc;
617   static struct GNUNET_HashCode zkey;
618
619   crc = GNUNET_new (struct CpsRunContext);
620   crc->phase = RP_PUT;
621   now = GNUNET_TIME_absolute_get ();
622   datastore = GNUNET_DATASTORE_connect (cfg);
623   if (NULL ==
624       GNUNET_DATASTORE_put (datastore,
625                             0,
626                             &zkey,
627                             4,
628                             "TEST",
629                             GNUNET_BLOCK_TYPE_TEST,
630                             0, 0, 0,
631                             GNUNET_TIME_relative_to_absolute
632                             (GNUNET_TIME_UNIT_SECONDS),
633                             0, 1,
634                             TIMEOUT,
635                             &run_tests, crc))
636   {
637     FPRINTF (stderr,
638              "%s",
639              "Test 'put' operation failed.\n");
640     ok = 1;
641     GNUNET_free (crc);
642   }
643 }
644
645
646 /**
647  * Entry point into the test. Determines which configuration / plugin
648  * we are running with based on the name of the binary and starts
649  * the peer.
650  *
651  * @param argc should be 1
652  * @param argv used to determine plugin / configuration name.
653  * @return 0 on success
654  */
655 int
656 main (int argc,
657       char *argv[])
658 {
659   char cfg_name[128];
660
661   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
662   GNUNET_snprintf (cfg_name,
663                    sizeof (cfg_name),
664                    "test_datastore_api_data_%s.conf",
665                    plugin_name);
666   if (0 !=
667       GNUNET_TESTING_peer_run ("test-gnunet-datastore",
668                                cfg_name,
669                                &run,
670                                NULL))
671     return 1;
672   return ok;
673 }
674
675 /* end of test_datastore_api.c */