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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @file datastore/test_datastore_api.c
20 * @brief Test for the basic datastore API.
21 * @author Christian Grothoff
24 * - test reservation failure
28 #include "gnunet_util_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_datastore_service.h"
31 #include "gnunet_datastore_plugin.h"
32 #include "gnunet_testing_lib.h"
36 * How long until we give up on transmitting the message?
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
40 #define ITERATIONS 256
43 * Handle to the datastore.
45 static struct GNUNET_DATASTORE_Handle *datastore;
47 static struct GNUNET_TIME_Absolute now;
50 * Value we return from #main().
55 * Name of plugin under test.
57 static const char *plugin_name;
70 static char buf[60000];
72 memset (buf, i, 8 * i);
98 static struct GNUNET_TIME_Absolute
99 get_expiration (int i)
101 struct GNUNET_TIME_Absolute av;
103 av.abs_value_us = now.abs_value_us + 20000000000LL - i * 1000 * 1000LL;
109 * Which phase of the process are we in?
114 * We are done (shutting down normally).
119 * We are adding new entries to the datastore.
128 RP_PUT_MULTIPLE_NEXT = 8,
130 RP_GET_MULTIPLE_NEXT = 10,
133 * Execution failed with some kind of error.
140 * Closure we give to all of the functions executing the
141 * benchmark. Could right now be global, but this allows
142 * us to theoretically run multiple clients "in parallel".
147 * Execution phase we are in.
151 struct GNUNET_HashCode key;
162 * Main state machine. Executes the next step of the test
163 * depending on the current state.
165 * @param cls the `struct CpsRunContext`
168 run_continuation (void *cls);
172 * Continuation called to notify client about result of an
173 * operation. Checks for errors, updates our iteration counters and
174 * continues execution with #run_continuation().
176 * @param cls the `struct CpsRunContext`
177 * @param success #GNUNET_SYSERR on failure
178 * @param min_expiration minimum expiration time required for content to be stored
179 * by the datacache at this time, zero for unknown
180 * @param msg NULL on success, otherwise an error message
183 check_success (void *cls,
185 struct GNUNET_TIME_Absolute min_expiration,
188 struct CpsRunContext *crc = cls;
190 if (GNUNET_OK != success)
192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
193 "Operation %d/%d not successful: `%s'\n",
197 crc->phase = RP_ERROR;
199 GNUNET_free_non_null (crc->data);
201 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
206 get_reserved (void *cls,
208 struct GNUNET_TIME_Absolute min_expiration,
211 struct CpsRunContext *crc = cls;
214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 "Error obtaining reservation: `%s'\n",
217 GNUNET_assert (0 < success);
219 GNUNET_SCHEDULER_add_now (&run_continuation,
225 check_value (void *cls,
226 const struct GNUNET_HashCode *key,
229 enum GNUNET_BLOCK_Type type,
232 uint32_t replication,
233 struct GNUNET_TIME_Absolute expiration,
236 struct CpsRunContext *crc = cls;
242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
243 "Value check failed (got NULL key) in %d/%d\n",
246 crc->phase = RP_ERROR;
247 GNUNET_SCHEDULER_add_now (&run_continuation,
253 "Check value got `%s' of size %u, type %d, expire %s\n",
254 GNUNET_h2s (key), (unsigned int) size, type,
255 GNUNET_STRINGS_absolute_time_to_string (expiration));
257 "Check value iteration %d wants size %u, type %d, expire %s\n", i,
258 (unsigned int) get_size (i), get_type (i),
259 GNUNET_STRINGS_absolute_time_to_string (get_expiration(i)));
261 GNUNET_assert (size == get_size (i));
262 GNUNET_assert (0 == memcmp (data, get_data (i), size));
263 GNUNET_assert (type == get_type (i));
264 GNUNET_assert (priority == get_priority (i));
265 GNUNET_assert (anonymity == get_anonymity (i));
266 GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
272 GNUNET_SCHEDULER_add_now (&run_continuation,
278 delete_value (void *cls,
279 const struct GNUNET_HashCode *key,
282 enum GNUNET_BLOCK_Type type,
285 uint32_t replication,
286 struct GNUNET_TIME_Absolute expiration,
289 struct CpsRunContext *crc = cls;
291 GNUNET_assert (NULL == crc->data);
292 GNUNET_assert (NULL != key);
295 crc->data = GNUNET_malloc (size);
296 GNUNET_memcpy (crc->data, data, size);
297 crc->phase = RP_DO_DEL;
298 GNUNET_SCHEDULER_add_now (&run_continuation,
304 check_nothing (void *cls,
305 const struct GNUNET_HashCode *key,
308 enum GNUNET_BLOCK_Type type,
311 uint32_t replication,
312 struct GNUNET_TIME_Absolute expiration,
315 struct CpsRunContext *crc = cls;
317 GNUNET_assert (key == NULL);
319 crc->phase = RP_RESERVE;
320 GNUNET_SCHEDULER_add_now (&run_continuation,
326 check_multiple (void *cls,
327 const struct GNUNET_HashCode *key,
330 enum GNUNET_BLOCK_Type type,
333 uint32_t replication,
334 struct GNUNET_TIME_Absolute expiration,
337 struct CpsRunContext *crc = cls;
339 GNUNET_assert (key != NULL);
342 case RP_GET_MULTIPLE:
343 crc->phase = RP_GET_MULTIPLE_NEXT;
344 crc->first_uid = uid;
346 case RP_GET_MULTIPLE_NEXT:
347 GNUNET_assert (uid != crc->first_uid);
348 crc->phase = RP_DONE;
352 crc->phase = RP_ERROR;
355 GNUNET_SCHEDULER_add_now (&run_continuation, crc);
360 * Main state machine. Executes the next step of the test
361 * depending on the current state.
363 * @param cls the `struct CpsRunContext`
366 run_continuation (void *cls)
368 struct CpsRunContext *crc = cls;
370 ok = (int) crc->phase;
371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372 "Test in phase %u\n",
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Executing PUT number %u\n",
380 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
381 GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
382 get_data (crc->i), get_type (crc->i),
383 get_priority (crc->i), get_anonymity (crc->i), 0,
384 get_expiration (crc->i), 1, 1,
385 &check_success, crc);
387 if (crc->i == ITERATIONS)
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Executing GET number %u\n",
395 GNUNET_CRYPTO_hash (&crc->i,
398 GNUNET_DATASTORE_get_key (datastore,
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Executing DEL number %u\n",
414 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
415 GNUNET_assert (NULL !=
416 GNUNET_DATASTORE_get_key (datastore,
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "Executing DO_DEL number %u\n",
433 crc->phase = RP_DELVALIDATE;
439 GNUNET_assert (NULL !=
440 GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
442 &check_success, crc));
446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447 "Executing DELVALIDATE number %u\n",
449 GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
450 GNUNET_assert (NULL !=
451 GNUNET_DATASTORE_get_key (datastore,
462 crc->phase = RP_PUT_MULTIPLE;
463 GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2,
466 case RP_PUT_MULTIPLE:
467 crc->phase = RP_PUT_MULTIPLE_NEXT;
468 GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
469 get_data (42), get_type (42), get_priority (42),
470 get_anonymity (42), 0, get_expiration (42), 1, 1,
471 &check_success, crc);
473 case RP_PUT_MULTIPLE_NEXT:
474 crc->phase = RP_GET_MULTIPLE;
475 GNUNET_DATASTORE_put (datastore, crc->rid,
485 &check_success, crc);
487 case RP_GET_MULTIPLE:
488 GNUNET_assert (NULL !=
489 GNUNET_DATASTORE_get_key (datastore,
499 case RP_GET_MULTIPLE_NEXT:
500 GNUNET_assert (NULL !=
501 GNUNET_DATASTORE_get_key (datastore,
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Finished, disconnecting\n");
514 GNUNET_DATASTORE_disconnect (datastore,
520 GNUNET_DATASTORE_disconnect (datastore,
530 * Function called with the result of the initial PUT operation. If
531 * the PUT succeeded, we start the actual benchmark loop, otherwise we
532 * bail out with an error.
536 * @param success #GNUNET_SYSERR on failure
537 * @param min_expiration minimum expiration time required for content to be stored
538 * by the datacache at this time, zero for unknown
539 * @param msg NULL on success, otherwise an error message
542 run_tests (void *cls,
544 struct GNUNET_TIME_Absolute min_expiration,
547 struct CpsRunContext *crc = cls;
552 GNUNET_SCHEDULER_add_now (&run_continuation,
557 "%s", "Test 'put' operation failed, key already exists (!?)\n");
558 GNUNET_DATASTORE_disconnect (datastore,
564 "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
566 GNUNET_DATASTORE_disconnect (datastore,
577 * Beginning of the actual execution of the benchmark.
578 * Performs a first test operation (PUT) to verify that
579 * the plugin works at all.
582 * @param cfg configuration to use
583 * @param peer peer handle (unused)
587 const struct GNUNET_CONFIGURATION_Handle *cfg,
588 struct GNUNET_TESTING_Peer *peer)
590 struct CpsRunContext *crc;
591 static struct GNUNET_HashCode zkey;
593 crc = GNUNET_new (struct CpsRunContext);
595 now = GNUNET_TIME_absolute_get ();
596 datastore = GNUNET_DATASTORE_connect (cfg);
598 GNUNET_DATASTORE_put (datastore,
603 GNUNET_BLOCK_TYPE_TEST,
605 GNUNET_TIME_relative_to_absolute
606 (GNUNET_TIME_UNIT_SECONDS),
612 "Test 'put' operation failed.\n");
620 * Function invoked to notify service of disk utilization
624 * @param delta change in disk utilization,
625 * 0 for "reset to empty"
628 duc_dummy (void *cls,
631 /* intentionally empty */
636 * check if plugin is actually working
639 test_plugin (const char *cfg_name)
642 struct GNUNET_CONFIGURATION_Handle *cfg;
643 struct GNUNET_DATASTORE_PluginFunctions *api;
644 struct GNUNET_DATASTORE_PluginEnvironment env;
646 cfg = GNUNET_CONFIGURATION_create ();
648 GNUNET_CONFIGURATION_load (cfg,
651 GNUNET_CONFIGURATION_destroy (cfg);
653 "Failed to load configuration %s\n",
657 memset (&env, 0, sizeof (env));
659 env.duc = &duc_dummy;
660 GNUNET_snprintf (libname,
662 "libgnunet_plugin_datastore_%s",
664 api = GNUNET_PLUGIN_load (libname, &env);
667 GNUNET_CONFIGURATION_destroy (cfg);
669 "Failed to load plugin `%s'\n",
673 GNUNET_PLUGIN_unload (libname, api);
674 GNUNET_CONFIGURATION_destroy (cfg);
680 * Entry point into the test. Determines which configuration / plugin
681 * we are running with based on the name of the binary and starts
684 * @param argc should be 1
685 * @param argv used to determine plugin / configuration name.
686 * @return 0 on success
695 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
696 GNUNET_snprintf (cfg_name,
698 "test_datastore_api_data_%s.conf",
700 ret = test_plugin (cfg_name);
703 /* run actual test */
705 GNUNET_TESTING_peer_run ("test-gnunet-datastore",
713 /* end of test_datastore_api.c */