use gnunetcheck for the DB
[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 struct FragmentClosure
106 {
107   uint8_t n;
108   uint64_t flags[16];
109   struct GNUNET_MULTICAST_MessageHeader *msg[16];
110 };
111
112 static int
113 fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2,
114              enum GNUNET_PSYCSTORE_MessageFlags flags)
115 {
116   struct FragmentClosure *fcls = cls;
117   struct GNUNET_MULTICAST_MessageHeader *msg1 = fcls->msg[fcls->n];
118   uint64_t flags1 = fcls->flags[fcls->n++];
119   int ret;
120
121   if (flags1 == flags && msg1->header.size == msg2->header.size
122       && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size)))
123   {
124     LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n",
125          GNUNET_ntohll (msg1->fragment_id));
126     ret = GNUNET_YES;
127   }
128   else
129   {
130     LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n",
131          GNUNET_ntohll (msg1->fragment_id));
132     ret = GNUNET_SYSERR;
133   }
134
135   GNUNET_free (msg2);
136   return ret;
137 }
138
139
140 struct StateClosure {
141   size_t n;
142   char *name[16];
143   void *value[16];
144   size_t value_size[16];
145 };
146
147 static int
148 state_cb (void *cls, const char *name, const void *value, uint32_t value_size)
149 {
150   struct StateClosure *scls = cls;
151   const void *val = scls->value[scls->n];
152   size_t val_size = scls->value_size[scls->n++];
153
154   /* FIXME: check name */
155
156   return value_size == val_size && 0 == memcmp (value, val, val_size)
157     ? GNUNET_YES
158     : GNUNET_SYSERR;
159 }
160
161
162 static void
163 run (void *cls, char *const *args, const char *cfgfile,
164      const struct GNUNET_CONFIGURATION_Handle *cfg)
165 {
166   struct GNUNET_PSYCSTORE_PluginFunctions *db;
167
168   ok = 1;
169   db = load_plugin (cfg);
170   if (NULL == db)
171   {
172     FPRINTF (stderr,
173              "%s",
174              "Failed to initialize PSYCstore.  "
175              "Database likely not setup, skipping test.\n");
176     ok = 77;
177     return;
178   }
179
180   /* Store & test membership */
181
182   LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");
183
184   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
185   slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
186
187   GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
188                                                   &channel_pub_key);
189   GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
190
191   LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");
192
193   GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
194                                                     &slave_pub_key, GNUNET_YES,
195                                                     4, 2, 1));
196
197   LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");
198
199   GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
200                                                     &slave_pub_key, 4));
201
202   GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
203                                                     &slave_pub_key, 2));
204
205   GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
206                                                    &slave_pub_key, 1));
207
208   /* Store & get messages */
209
210   LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");
211
212   struct GNUNET_MULTICAST_MessageHeader *msg
213     = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
214   GNUNET_assert (msg != NULL);
215
216   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
217   msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));
218
219   uint64_t fragment_id = INT64_MAX - 1;
220   msg->fragment_id = GNUNET_htonll (fragment_id);
221
222   uint64_t message_id = INT64_MAX - 10;
223   msg->message_id = GNUNET_htonll (message_id);
224
225   uint64_t group_generation = INT64_MAX - 3;
226   msg->group_generation = GNUNET_htonll (group_generation);
227
228   msg->hop_counter = htonl (9);
229   msg->fragment_offset = GNUNET_htonll (0);
230   msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);
231
232   GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));
233
234   msg->purpose.size = htonl (ntohs (msg->header.size)
235                              - sizeof (msg->header)
236                              - sizeof (msg->hop_counter)
237                              - sizeof (msg->signature));
238   msg->purpose.purpose = htonl (234);
239   GNUNET_assert (GNUNET_OK ==
240                  GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));
241
242   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
243
244   struct FragmentClosure fcls = { 0 };
245   fcls.n = 0;
246   fcls.msg[0] = msg;
247   fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;
248
249   GNUNET_assert (
250     GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
251                                      fcls.flags[0]));
252
253   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
254
255   uint64_t ret_frags = 0;
256   GNUNET_assert (
257     GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
258                                    fragment_id, fragment_id,
259                                    &ret_frags, fragment_cb, &fcls));
260   GNUNET_assert (fcls.n == 1);
261
262   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id+1);
263
264   ret_frags = 0;
265   GNUNET_assert (
266     GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
267                                    fragment_id+1, fragment_id+1,
268                                    &ret_frags, fragment_cb, &fcls));
269   GNUNET_assert (fcls.n == 1);
270
271   // FIXME: test fragment_get_latest and message_get_latest
272
273   LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");
274
275   fcls.n = 0;
276
277   GNUNET_assert (
278     GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
279                                            GNUNET_ntohll (msg->message_id),
280                                            GNUNET_ntohll (msg->fragment_offset),
281                                            fragment_cb, &fcls));
282   GNUNET_assert (fcls.n == 1);
283
284   LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
285
286   GNUNET_assert (
287     GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
288                                         GNUNET_ntohll (msg->message_id),
289                                         GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
290
291   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
292
293   fcls.n = 0;
294   fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;
295
296   GNUNET_assert (
297     GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
298                                    fragment_id, fragment_id,
299                                    &ret_frags, fragment_cb, &fcls));
300
301   GNUNET_assert (fcls.n == 1);
302
303   LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
304
305   struct GNUNET_MULTICAST_MessageHeader *msg1
306     = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));
307
308   GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));
309
310   msg1->fragment_id = GNUNET_htonll (INT64_MAX);
311   msg1->fragment_offset = GNUNET_htonll (32768);
312
313   fcls.n = 0;
314   fcls.msg[1] = msg1;
315   fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;
316
317   GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
318                                                   fcls.flags[1]));
319
320   LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");
321
322   GNUNET_assert (
323     GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
324                                   message_id, message_id, 0,
325                                   &ret_frags, fragment_cb, &fcls));
326   GNUNET_assert (fcls.n == 2 && ret_frags == 2);
327
328   /* Message counters */
329
330   LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");
331
332   fragment_id = 0;
333   message_id = 0;
334   group_generation = 0;
335   GNUNET_assert (
336     GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
337                                            &fragment_id, &message_id,
338                                            &group_generation)
339     && fragment_id == GNUNET_ntohll (msg1->fragment_id)
340     && message_id == GNUNET_ntohll (msg1->message_id)
341     && group_generation == GNUNET_ntohll (msg1->group_generation));
342
343   /* Modify state */
344
345   LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");
346
347   LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
348
349   message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
350   GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
351                                                       message_id, 0));
352
353   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
354                                                    GNUNET_PSYC_OP_ASSIGN,
355                                                    "_foo",
356                                                    C2ARG("one two three")));
357
358   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
359                                                    GNUNET_PSYC_OP_ASSIGN,
360                                                    "_foo_bar", slave_key,
361                                                    sizeof (*slave_key)));
362
363   GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
364                                                     message_id));
365
366   LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");
367
368   struct StateClosure scls = { 0 };
369   scls.n = 0;
370   scls.value[0] = "one two three";
371   scls.value_size[0] = strlen ("one two three");
372
373   GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
374                                              state_cb, &scls));
375   GNUNET_assert (scls.n == 1);
376
377   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");
378
379   scls.n = 0;
380   scls.value[1] = slave_key;
381   scls.value_size[1] = sizeof (*slave_key);
382
383   GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
384                                                     "_foo", state_cb, &scls));
385   GNUNET_assert (scls.n == 2);
386
387   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
388
389   scls.n = 0;
390   GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
391                                                     state_cb, &scls));
392   GNUNET_assert (scls.n == 0);
393
394   LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");
395
396   GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
397                                                        &channel_pub_key));
398
399   LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
400
401   scls.n = 0;
402   GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
403                                                      state_cb, &scls));
404   GNUNET_assert (scls.n == 2);
405
406   /* State counters */
407
408   LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");
409
410   uint64_t max_state_msg_id = 0;
411   GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
412                                                       &max_state_msg_id)
413                  && max_state_msg_id == message_id);
414
415   /* State sync */
416
417   LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");
418
419   scls.n = 0;
420   scls.value[0] = channel_key;
421   scls.value_size[0] = sizeof (*channel_key);
422   scls.value[1] = "three two one";
423   scls.value_size[1] = strlen ("three two one");
424
425   GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));
426
427   GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
428                                                      "_sync_bar", scls.value[0],
429                                                      scls.value_size[0]));
430
431   GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
432                                                      "_sync_foo", scls.value[1],
433                                                      scls.value_size[1]));
434
435   GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
436                                                   max_state_msg_id,
437                                                   INT64_MAX - 5));
438
439   GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
440                                                     "_foo", state_cb, &scls));
441   GNUNET_assert (scls.n == 0);
442
443   GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
444                                                     "_sync", state_cb, &scls));
445   GNUNET_assert (scls.n == 2);
446
447   scls.n = 0;
448   GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
449                                                     state_cb, &scls));
450   GNUNET_assert (scls.n == 2);
451
452   /* Modify state after sync */
453
454   LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
455
456   message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
457   GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
458                                                       message_id,
459                                                       message_id - max_state_msg_id));
460
461   GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
462                                                    GNUNET_PSYC_OP_ASSIGN,
463                                                    "_sync_foo",
464                                                    C2ARG("five six seven")));
465
466   GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
467                                                     message_id));
468
469   /* Reset state */
470
471   LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");
472
473   scls.n = 0;
474   GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
475   GNUNET_assert (scls.n == 0);
476
477   ok = 0;
478
479   if (NULL != channel_key)
480   {
481     GNUNET_free (channel_key);
482     channel_key = NULL;
483   }
484   if (NULL != slave_key)
485   {
486     GNUNET_free (slave_key);
487     slave_key = NULL;
488   }
489
490   unload_plugin (db);
491 }
492
493
494 int
495 main (int argc, char *argv[])
496 {
497   char cfg_name[128];
498   char *const xargv[] = {
499     "test-plugin-psycstore",
500     "-c", cfg_name,
501     "-L", LOG_LEVEL,
502     NULL
503   };
504   struct GNUNET_GETOPT_CommandLineOption options[] = {
505     GNUNET_GETOPT_OPTION_END
506   };
507   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
508   GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL);
509   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
510   GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf",
511                    plugin_name);
512   GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
513                       "test-plugin-psycstore", "nohelp", options, &run, NULL);
514
515   if ( (0 != ok) &&
516        (77 != ok) )
517     FPRINTF (stderr, "Missed some testcases: %d\n", ok);
518
519 #if ! DEBUG_PSYCSTORE
520   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
521 #endif
522
523   return ok;
524 }
525
526 /* end of test_plugin_psycstore.c */