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