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