2 This file is part of GNUnet.
3 Copyright (C) 2004, 2005, 2006, 2007, 2009, 2015 GNUnet e.V.
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.
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.
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.
21 * @file datastore/test_datastore_api.c
22 * @brief Test for the basic datastore API.
23 * @author Christian Grothoff
26 * - test reservation failure
30 #include "gnunet_util_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_datastore_service.h"
33 #include "gnunet_datastore_plugin.h"
34 #include "gnunet_testing_lib.h"
38 * How long until we give up on transmitting the message?
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
42 #define ITERATIONS 256
45 * Handle to the datastore.
47 static struct GNUNET_DATASTORE_Handle *datastore;
49 static struct GNUNET_TIME_Absolute now;
52 * Value we return from #main().
57 * Name of plugin under test.
59 static const char *plugin_name;
72 static char buf[60000];
74 memset (buf, i, 8 * i);
100 static struct GNUNET_TIME_Absolute
101 get_expiration (int i)
103 struct GNUNET_TIME_Absolute av;
105 av.abs_value_us = now.abs_value_us + 20000000000LL - i * 1000 * 1000LL;
111 * Which phase of the process are we in?
116 * We are done (shutting down normally).
121 * We are adding new entries to the datastore.
130 RP_PUT_MULTIPLE_NEXT = 8,
132 RP_GET_MULTIPLE_NEXT = 10,
134 RP_UPDATE_VALIDATE = 12,
137 * Execution failed with some kind of error.
144 * Closure we give to all of the functions executing the
145 * benchmark. Could right now be global, but this allows
146 * us to theoretically run multiple clients "in parallel".
151 * Execution phase we are in.
155 struct GNUNET_HashCode key;
168 * Main state machine. Executes the next step of the test
169 * depending on the current state.
171 * @param cls the `struct CpsRunContext`
174 run_continuation (void *cls);
178 * Continuation called to notify client about result of an
179 * operation. Checks for errors, updates our iteration counters and
180 * continues execution with #run_continuation().
182 * @param cls the `struct CpsRunContext`
183 * @param success #GNUNET_SYSERR on failure
184 * @param min_expiration minimum expiration time required for content to be stored
185 * by the datacache at this time, zero for unknown
186 * @param msg NULL on success, otherwise an error message
189 check_success (void *cls,
191 struct GNUNET_TIME_Absolute min_expiration,
194 struct CpsRunContext *crc = cls;
196 if (GNUNET_OK != success)
198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
199 "Operation %d/%d not successful: `%s'\n",
203 crc->phase = RP_ERROR;
205 GNUNET_free_non_null (crc->data);
207 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
212 get_reserved (void *cls,
214 struct GNUNET_TIME_Absolute min_expiration,
217 struct CpsRunContext *crc = cls;
220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
221 "Error obtaining reservation: `%s'\n",
223 GNUNET_assert (0 < success);
225 GNUNET_SCHEDULER_add_now (&run_continuation,
231 check_value (void *cls,
232 const struct GNUNET_HashCode *key,
235 enum GNUNET_BLOCK_Type type,
238 struct GNUNET_TIME_Absolute expiration,
241 struct CpsRunContext *crc = cls;
247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
248 "Value check failed (got NULL key) in %d/%d\n",
251 crc->phase = RP_ERROR;
252 GNUNET_SCHEDULER_add_now (&run_continuation,
258 "Check value got `%s' of size %u, type %d, expire %s\n",
259 GNUNET_h2s (key), (unsigned int) size, type,
260 GNUNET_STRINGS_absolute_time_to_string (expiration));
262 "Check value iteration %d wants size %u, type %d, expire %s\n", i,
263 (unsigned int) get_size (i), get_type (i),
264 GNUNET_STRINGS_absolute_time_to_string (get_expiration(i)));
266 GNUNET_assert (size == get_size (i));
267 GNUNET_assert (0 == memcmp (data, get_data (i), size));
268 GNUNET_assert (type == get_type (i));
269 GNUNET_assert (priority == get_priority (i));
270 GNUNET_assert (anonymity == get_anonymity (i));
271 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
278 GNUNET_SCHEDULER_add_now (&run_continuation,
284 delete_value (void *cls,
285 const struct GNUNET_HashCode *key,
288 enum GNUNET_BLOCK_Type type,
291 struct GNUNET_TIME_Absolute expiration,
294 struct CpsRunContext *crc = cls;
296 GNUNET_assert (NULL == crc->data);
297 GNUNET_assert (NULL != key);
300 crc->data = GNUNET_malloc (size);
301 GNUNET_memcpy (crc->data, data, size);
302 crc->phase = RP_DO_DEL;
303 GNUNET_SCHEDULER_add_now (&run_continuation,
309 check_nothing (void *cls,
310 const struct GNUNET_HashCode *key,
313 enum GNUNET_BLOCK_Type type,
316 struct GNUNET_TIME_Absolute expiration,
319 struct CpsRunContext *crc = cls;
321 GNUNET_assert (key == NULL);
323 crc->phase = RP_RESERVE;
324 GNUNET_SCHEDULER_add_now (&run_continuation,
330 check_multiple (void *cls,
331 const struct GNUNET_HashCode *key,
334 enum GNUNET_BLOCK_Type type,
337 struct GNUNET_TIME_Absolute expiration,
340 struct CpsRunContext *crc = cls;
342 GNUNET_assert (key != NULL);
345 case RP_GET_MULTIPLE:
346 crc->phase = RP_GET_MULTIPLE_NEXT;
347 crc->first_uid = uid;
350 case RP_GET_MULTIPLE_NEXT:
351 GNUNET_assert (uid != crc->first_uid);
352 crc->phase = RP_UPDATE;
356 crc->phase = RP_ERROR;
359 if (priority == get_priority (42))
361 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
366 check_update (void *cls,
367 const struct GNUNET_HashCode *key,
370 enum GNUNET_BLOCK_Type type,
373 struct GNUNET_TIME_Absolute expiration,
376 struct CpsRunContext *crc = cls;
378 GNUNET_assert (key != NULL);
379 if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
380 (priority == get_priority (42) + 100))
381 crc->phase = RP_DONE;
384 GNUNET_assert (size == get_size (43));
387 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
392 * Main state machine. Executes the next step of the test
393 * depending on the current state.
395 * @param cls the `struct CpsRunContext`
398 run_continuation (void *cls)
400 struct CpsRunContext *crc = cls;
402 ok = (int) crc->phase;
403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404 "Test in phase %u\n",
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410 "Executing PUT number %u\n",
412 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
413 GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
414 get_data (crc->i), get_type (crc->i),
415 get_priority (crc->i), get_anonymity (crc->i), 0,
416 get_expiration (crc->i), 1, 1,
417 &check_success, crc);
419 if (crc->i == ITERATIONS)
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Executing GET number %u\n",
427 GNUNET_CRYPTO_hash (&crc->i,
430 GNUNET_DATASTORE_get_key (datastore,
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Executing DEL number %u\n",
445 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
446 GNUNET_assert (NULL !=
447 GNUNET_DATASTORE_get_key (datastore,
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Executing DO_DEL number %u\n",
463 crc->phase = RP_DELVALIDATE;
469 GNUNET_assert (NULL !=
470 GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
472 &check_success, crc));
476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
477 "Executing DELVALIDATE number %u\n",
479 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
480 GNUNET_assert (NULL !=
481 GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
482 get_type (crc->i), 1, 1,
483 &check_nothing, crc));
486 crc->phase = RP_PUT_MULTIPLE;
487 GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2,
490 case RP_PUT_MULTIPLE:
491 crc->phase = RP_PUT_MULTIPLE_NEXT;
492 GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
493 get_data (42), get_type (42), get_priority (42),
494 get_anonymity (42), 0, get_expiration (42), 1, 1,
495 &check_success, crc);
497 case RP_PUT_MULTIPLE_NEXT:
498 crc->phase = RP_GET_MULTIPLE;
499 GNUNET_DATASTORE_put (datastore, crc->rid,
509 &check_success, crc);
511 case RP_GET_MULTIPLE:
512 GNUNET_assert (NULL !=
513 GNUNET_DATASTORE_get_key (datastore,
517 &check_multiple, crc));
519 case RP_GET_MULTIPLE_NEXT:
520 GNUNET_assert (NULL !=
521 GNUNET_DATASTORE_get_key (datastore,
526 &check_multiple, crc));
529 GNUNET_assert (crc->uid > 0);
530 crc->phase = RP_UPDATE_VALIDATE;
531 GNUNET_DATASTORE_update (datastore,
533 get_expiration (42), 1,
535 &check_success, crc);
537 case RP_UPDATE_VALIDATE:
538 GNUNET_assert (NULL !=
539 GNUNET_DATASTORE_get_key (datastore,
544 &check_update, crc));
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Finished, disconnecting\n");
549 GNUNET_DATASTORE_disconnect (datastore,
555 GNUNET_DATASTORE_disconnect (datastore,
565 * Function called with the result of the initial PUT operation. If
566 * the PUT succeeded, we start the actual benchmark loop, otherwise we
567 * bail out with an error.
571 * @param success #GNUNET_SYSERR on failure
572 * @param min_expiration minimum expiration time required for content to be stored
573 * by the datacache at this time, zero for unknown
574 * @param msg NULL on success, otherwise an error message
577 run_tests (void *cls,
579 struct GNUNET_TIME_Absolute min_expiration,
582 struct CpsRunContext *crc = cls;
587 GNUNET_SCHEDULER_add_now (&run_continuation,
592 "%s", "Test 'put' operation failed, key already exists (!?)\n");
593 GNUNET_DATASTORE_disconnect (datastore,
599 "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
601 GNUNET_DATASTORE_disconnect (datastore,
612 * Beginning of the actual execution of the benchmark.
613 * Performs a first test operation (PUT) to verify that
614 * the plugin works at all.
617 * @param cfg configuration to use
618 * @param peer peer handle (unused)
622 const struct GNUNET_CONFIGURATION_Handle *cfg,
623 struct GNUNET_TESTING_Peer *peer)
625 struct CpsRunContext *crc;
626 static struct GNUNET_HashCode zkey;
628 crc = GNUNET_new (struct CpsRunContext);
630 now = GNUNET_TIME_absolute_get ();
631 datastore = GNUNET_DATASTORE_connect (cfg);
633 GNUNET_DATASTORE_put (datastore,
638 GNUNET_BLOCK_TYPE_TEST,
640 GNUNET_TIME_relative_to_absolute
641 (GNUNET_TIME_UNIT_SECONDS),
647 "Test 'put' operation failed.\n");
655 * Function invoked to notify service of disk utilization
659 * @param delta change in disk utilization,
660 * 0 for "reset to empty"
663 duc_dummy (void *cls,
666 /* intentionally empty */
671 * check if plugin is actually working
674 test_plugin (const char *cfg_name)
677 struct GNUNET_CONFIGURATION_Handle *cfg;
678 struct GNUNET_DATASTORE_PluginFunctions *api;
679 struct GNUNET_DATASTORE_PluginEnvironment env;
681 cfg = GNUNET_CONFIGURATION_create ();
683 GNUNET_CONFIGURATION_load (cfg,
686 GNUNET_CONFIGURATION_destroy (cfg);
688 "Failed to load configuration %s\n",
692 memset (&env, 0, sizeof (env));
694 env.duc = &duc_dummy;
695 GNUNET_snprintf (libname,
697 "libgnunet_plugin_datastore_%s",
699 api = GNUNET_PLUGIN_load (libname, &env);
702 GNUNET_CONFIGURATION_destroy (cfg);
704 "Failed to load plugin `%s'\n",
708 GNUNET_PLUGIN_unload (libname, api);
709 GNUNET_CONFIGURATION_destroy (cfg);
715 * Entry point into the test. Determines which configuration / plugin
716 * we are running with based on the name of the binary and starts
719 * @param argc should be 1
720 * @param argv used to determine plugin / configuration name.
721 * @return 0 on success
730 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
731 GNUNET_snprintf (cfg_name,
733 "test_datastore_api_data_%s.conf",
735 ret = test_plugin (cfg_name);
738 /* run actual test */
740 GNUNET_TESTING_peer_run ("test-gnunet-datastore",
748 /* end of test_datastore_api.c */