merge benchmark changes
[oweals/gnunet.git] / src / psycstore / test_plugin_psycstore.c
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2013 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 /**
22  * @author Gabor X Toth
23  * @author Christian Grothoff
24  *
25  * @file
26  * Test for the PSYCstore plugins.
27  */
28
29 #include <inttypes.h>
30
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_testing_lib.h"
34 #include "gnunet_psycstore_plugin.h"
35 #include "gnunet_psycstore_service.h"
36 #include "gnunet_multicast_service.h"
37
38 #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
39 #if DEBUG_PSYCSTORE
40 # define LOG_LEVEL "DEBUG"
41 #else
42 # define LOG_LEVEL "WARNING"
43 #endif
44
45 #define C2ARG(str) str, (sizeof (str) - 1)
46
47 #define LOG(kind,...)                                                          \
48   GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__)
49
50 static int ok;
51
52 /**
53  * Name of plugin under test.
54  */
55 static const char *plugin_name;
56
57 static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
58 static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
59
60 static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
61 static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
62
63 /**
64  * Function called when the service shuts down.  Unloads our psycstore
65  * plugin.
66  *
67  * @param api api to unload
68  */
69 static void
70 unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api)
71 {
72   char *libname;
73
74   GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
75   GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
76   GNUNET_free (libname);
77 }
78
79
80 /**
81  * Load the psycstore plugin.
82  *
83  * @param cfg configuration to pass
84  * @return NULL on error
85  */
86 static struct GNUNET_PSYCSTORE_PluginFunctions *
87 load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
88 {
89   struct GNUNET_PSYCSTORE_PluginFunctions *ret;
90   char *libname;
91
92   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"),
93               plugin_name);
94   GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
95   if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg)))
96   {
97     FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name);
98     return NULL;
99   }
100   GNUNET_free (libname);
101   return ret;
102 }
103
104
105 #define MAX_MSG 16
106
107 struct FragmentClosure
108 {
109   uint8_t n;
110   uint64_t flags[MAX_MSG];
111   struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG];
112 };
113
114 static int
115 fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2,
116              enum GNUNET_PSYCSTORE_MessageFlags flags)
117 {
118   struct FragmentClosure *fcls = cls;
119   struct GNUNET_MULTICAST_MessageHeader *msg1;
120   uint64_t flags1;
121   int ret;
122
123   if (fcls->n >= MAX_MSG)
124     {
125       GNUNET_break (0);
126       return GNUNET_SYSERR;
127     }
128   msg1 = fcls->msg[fcls->n];
129   flags1 = fcls->flags[fcls->n++];
130   if (NULL == msg1)
131     {
132       GNUNET_break (0);
133       return GNUNET_SYSERR;
134     }
135
136   if (flags1 == flags && msg1->header.size == msg2->header.size
137       && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size)))
138   {
139     LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n",
140          GNUNET_ntohll (msg1->fragment_id));
141     ret = GNUNET_YES;
142   }
143   else
144   {
145     LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n",
146          GNUNET_ntohll (msg1->fragment_id));
147     ret = GNUNET_SYSERR;
148   }
149
150   GNUNET_free (msg2);
151   return ret;
152 }
153
154
155 struct StateClosure {
156   size_t n;
157   char *name[16];
158   void *value[16];
159   size_t value_size[16];
160 };
161
162 static int
163 state_cb (void *cls, const char *name, const void *value, uint32_t value_size)
164 {
165   struct StateClosure *scls = cls;
166   const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST!
167   size_t val_size = scls->value_size[scls->n++];
168
169   /* FIXME: check name */
170
171   LOG (GNUNET_ERROR_TYPE_DEBUG,
172        "  name = %s, value_size = %u\n",
173        name, value_size);
174
175   return GNUNET_YES;
176   return value_size == val_size && 0 == memcmp (value, val, val_size)
177     ? GNUNET_YES
178     : GNUNET_SYSERR;
179 }
180
181
182 static void
183 run (void *cls, char *const *args, const char *cfgfile,
184      const struct GNUNET_CONFIGURATION_Handle *cfg)
185 {
186   struct GNUNET_PSYCSTORE_PluginFunctions *db;
187
188   ok = 1;
189   db = load_plugin (cfg);
190   if (NULL == db)
191   {
192     FPRINTF (stderr,
193              "%s",
194              "Failed to initialize PSYCstore.  "
195              "Database likely not setup, skipping test.\n");
196     ok = 77;
197     return;
198   }
199
200   /* Store & test membership */
201
202   LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");
203
204   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
205   slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
206
207   GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
208                                                   &channel_pub_key);
209   GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
210
211   LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");
212
213   GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
214                                                     &slave_pub_key, GNUNET_YES,
215                                                     4, 2, 1));
216
217   LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");
218
219   GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
220                                                     &slave_pub_key, 4));
221
222   GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
223                                                     &slave_pub_key, 2));
224
225   GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
226                                                    &slave_pub_key, 1));
227
228   /* Store & get messages */
229
230   LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");
231
232   struct GNUNET_MULTICAST_MessageHeader *msg
233     = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
234   GNUNET_assert (msg != NULL);
235
236   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
237   msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));
238
239   uint64_t fragment_id = INT64_MAX - 1;
240   msg->fragment_id = GNUNET_htonll (fragment_id);
241
242   uint64_t message_id = INT64_MAX - 10;
243   msg->message_id = GNUNET_htonll (message_id);
244
245   uint64_t group_generation = INT64_MAX - 3;
246   msg->group_generation = GNUNET_htonll (group_generation);
247
248   msg->hop_counter = htonl (9);
249   msg->fragment_offset = GNUNET_htonll (0);
250   msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);
251
252   GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));
253
254   msg->purpose.size = htonl (ntohs (msg->header.size)
255                              - sizeof (msg->header)
256                              - sizeof (msg->hop_counter)
257                              - sizeof (msg->signature));
258   msg->purpose.purpose = htonl (234);
259   GNUNET_assert (GNUNET_OK ==
260                  GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));
261
262   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
263
264   struct FragmentClosure fcls = { 0 };
265   fcls.n = 0;
266   fcls.msg[0] = msg;
267   fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;
268
269   GNUNET_assert (
270     GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
271                                      fcls.flags[0]));
272
273   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
274
275   uint64_t ret_frags = 0;
276   GNUNET_assert (
277     GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
278                                    fragment_id, fragment_id,
279                                    &ret_frags, fragment_cb, &fcls));
280   GNUNET_assert (fcls.n == 1);
281
282   LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");
283
284   fcls.n = 0;
285   GNUNET_assert (
286     GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
287                                            GNUNET_ntohll (msg->message_id),
288                                            GNUNET_ntohll (msg->fragment_offset),
289                                            fragment_cb, &fcls));
290   GNUNET_assert (fcls.n == 1);
291
292   LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
293   GNUNET_assert (
294     GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
295                                         GNUNET_ntohll (msg->message_id),
296                                         GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
297   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
298
299   fcls.n = 0;
300   fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;
301
302   GNUNET_assert (
303     GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
304                                    fragment_id, fragment_id,
305                                    &ret_frags, fragment_cb, &fcls));
306
307   GNUNET_assert (fcls.n == 1);
308
309   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
310
311   struct GNUNET_MULTICAST_MessageHeader *msg1
312     = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));
313
314   GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));
315
316   msg1->fragment_id = GNUNET_htonll (INT64_MAX);
317   msg1->fragment_offset = GNUNET_htonll (32768);
318
319   fcls.n = 0;
320   fcls.msg[1] = msg1;
321   fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;
322
323   GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
324                                                   fcls.flags[1]));
325
326   LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");
327
328   GNUNET_assert (
329     GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
330                                   message_id, message_id, 0,
331                                   &ret_frags, fragment_cb, &fcls));
332   GNUNET_assert (fcls.n == 2 && ret_frags == 2);
333
334   /* Message counters */
335
336   LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");
337
338   fragment_id = 0;
339   message_id = 0;
340   group_generation = 0;
341   GNUNET_assert (
342     GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
343                                            &fragment_id, &message_id,
344                                            &group_generation)
345     && fragment_id == GNUNET_ntohll (msg1->fragment_id)
346     && message_id == GNUNET_ntohll (msg1->message_id)
347     && group_generation == GNUNET_ntohll (msg1->group_generation));
348
349   /* Modify state */
350
351   LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");
352
353   LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
354
355   message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
356   GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
357                                                       message_id, 0));
358
359   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
360                                                    GNUNET_PSYC_OP_ASSIGN,
361                                                    "_foo",
362                                                    C2ARG("one two three")));
363
364   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
365                                                    GNUNET_PSYC_OP_ASSIGN,
366                                                    "_foo_bar", slave_key,
367                                                    sizeof (*slave_key)));
368
369   GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
370                                                     message_id));
371
372   LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");
373
374   struct StateClosure scls = { 0 };
375   scls.n = 0;
376   scls.value[0] = "one two three";
377   scls.value_size[0] = strlen ("one two three");
378
379   GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
380                                              state_cb, &scls));
381   GNUNET_assert (scls.n == 1);
382
383   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");
384
385   scls.n = 0;
386   scls.value[1] = slave_key;
387   scls.value_size[1] = sizeof (*slave_key);
388
389   GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
390                                                     "_foo", state_cb, &scls));
391   GNUNET_assert (scls.n == 2);
392
393   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
394
395   scls.n = 0;
396   GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
397                                                     state_cb, &scls));
398   GNUNET_assert (scls.n == 0);
399
400   LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");
401
402   GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
403                                                        &channel_pub_key));
404
405   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
406
407   scls.n = 0;
408   GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
409                                                      state_cb, &scls));
410   GNUNET_assert (scls.n == 2);
411
412   /* State counters */
413
414   LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");
415
416   uint64_t max_state_msg_id = 0;
417   GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
418                                                       &max_state_msg_id)
419                  && max_state_msg_id == message_id);
420
421   /* State sync */
422
423   LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");
424
425   scls.n = 0;
426   scls.value[0] = channel_key;
427   scls.value_size[0] = sizeof (*channel_key);
428   scls.value[1] = "three two one";
429   scls.value_size[1] = strlen ("three two one");
430
431   GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));
432
433   GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
434                                                      "_sync_bar", scls.value[0],
435                                                      scls.value_size[0]));
436
437   GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
438                                                      "_sync_foo", scls.value[1],
439                                                      scls.value_size[1]));
440
441   GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
442                                                   max_state_msg_id,
443                                                   INT64_MAX - 5));
444
445   GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
446                                                     "_foo", state_cb, &scls));
447   GNUNET_assert (scls.n == 0);
448
449   GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
450                                                     "_sync", state_cb, &scls));
451   GNUNET_assert (scls.n == 2);
452
453   scls.n = 0;
454   GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
455                                                     state_cb, &scls));
456   GNUNET_assert (scls.n == 2);
457
458   /* Modify state after sync */
459
460   LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
461
462   message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
463   GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
464                                                       message_id,
465                                                       message_id - max_state_msg_id));
466
467   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
468                                                    GNUNET_PSYC_OP_ASSIGN,
469                                                    "_sync_foo",
470                                                    C2ARG("five six seven")));
471
472   GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
473                                                     message_id));
474
475   /* Reset state */
476
477   LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");
478
479   scls.n = 0;
480   GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
481   GNUNET_assert (scls.n == 0);
482
483   ok = 0;
484
485   if (NULL != channel_key)
486   {
487     GNUNET_free (channel_key);
488     channel_key = NULL;
489   }
490   if (NULL != slave_key)
491   {
492     GNUNET_free (slave_key);
493     slave_key = NULL;
494   }
495
496   unload_plugin (db);
497 }
498
499
500 int
501 main (int argc, char *argv[])
502 {
503   char cfg_name[128];
504   char *const xargv[] = {
505     "test-plugin-psycstore",
506     "-c", cfg_name,
507     "-L", LOG_LEVEL,
508     NULL
509   };
510   struct GNUNET_GETOPT_CommandLineOption options[] = {
511     GNUNET_GETOPT_OPTION_END
512   };
513   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
514   GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL);
515   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
516   GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf",
517                    plugin_name);
518   GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
519                       "test-plugin-psycstore", "nohelp", options, &run, NULL);
520
521   if ( (0 != ok) &&
522        (77 != ok) )
523     FPRINTF (stderr, "Missed some testcases: %d\n", ok);
524
525 #if ! DEBUG_PSYCSTORE
526   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
527 #endif
528
529   return ok;
530 }
531
532 /* end of test_plugin_psycstore.c */