4aae5e122b4f145b86f047e6bf5800d5ee880f4e
[oweals/gnunet.git] / src / psyc / test_psyc.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  * @file psyc/test_psyc.c
23  * @brief Tests for the PSYC API.
24  * @author Gabor X Toth
25  * @author Christian Grothoff
26  */
27
28 #include <inttypes.h>
29
30 #include "platform.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_common.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_testing_lib.h"
35 #include "gnunet_psyc_util_lib.h"
36 #include "gnunet_psyc_service.h"
37 #include "gnunet_core_service.h"
38
39 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
40
41 /**
42  * Return value from 'main'.
43  */
44 int res;
45
46 const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48 struct GNUNET_CORE_Handle *core;
49 struct GNUNET_PeerIdentity this_peer;
50
51 /**
52  * Handle for task for timeout termination.
53  */
54 struct GNUNET_SCHEDULER_Task * end_badly_task;
55
56 struct GNUNET_PSYC_Master *mst;
57 struct GNUNET_PSYC_Slave *slv;
58
59 struct GNUNET_PSYC_Channel *mst_chn, *slv_chn;
60
61 struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
62 struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
63
64 struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
65 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
66
67 struct TransmitClosure
68 {
69   struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit;
70   struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit;
71   struct GNUNET_PSYC_Environment *env;
72   struct GNUNET_PSYC_Modifier *mod;
73   char *data[16];
74   const char *mod_value;
75   size_t mod_value_size;
76   uint8_t data_delay[16];
77   uint8_t data_count;
78   uint8_t paused;
79   uint8_t n;
80 };
81
82 struct TransmitClosure *tmit;
83
84 uint8_t join_req_count, end_count;
85
86 enum
87 {
88   TEST_NONE                         = 0,
89   TEST_MASTER_START                 = 1,
90   TEST_SLAVE_JOIN_REJECT            = 2,
91   TEST_SLAVE_JOIN_ACCEPT            = 3,
92   TEST_SLAVE_ADD                    = 4,
93   TEST_SLAVE_REMOVE                 = 5,
94   TEST_SLAVE_TRANSMIT               = 6,
95   TEST_MASTER_TRANSMIT              = 7,
96   TEST_MASTER_HISTORY_REPLAY_LATEST = 8,
97   TEST_SLAVE_HISTORY_REPLAY_LATEST  = 9,
98   TEST_MASTER_HISTORY_REPLAY       = 10,
99   TEST_SLAVE_HISTORY_REPLAY        = 11,
100   TEST_MASTER_STATE_GET            = 12,
101   TEST_SLAVE_STATE_GET             = 13,
102   TEST_MASTER_STATE_GET_PREFIX     = 14,
103   TEST_SLAVE_STATE_GET_PREFIX      = 15,
104 } test;
105
106
107 void
108 master_transmit ();
109
110 void
111 master_history_replay_latest ();
112
113
114 void master_stopped (void *cls)
115 {
116   if (NULL != tmit)
117   {
118     GNUNET_PSYC_env_destroy (tmit->env);
119     GNUNET_free (tmit);
120     tmit = NULL;
121   }
122   GNUNET_SCHEDULER_shutdown ();
123 }
124
125 void slave_parted (void *cls)
126 {
127   if (NULL != mst)
128   {
129     GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL);
130     mst = NULL;
131   }
132   else
133     master_stopped (NULL);
134 }
135
136 /**
137  * Clean up all resources used.
138  */
139 void
140 cleanup ()
141 {
142   if (NULL != core)
143   {
144     GNUNET_CORE_disconnect (core);
145     core = NULL;
146   }
147   if (NULL != slv)
148   {
149     GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL);
150     slv = NULL;
151   }
152   else
153     slave_parted (NULL);
154 }
155
156
157 /**
158  * Terminate the test case (failure).
159  *
160  * @param cls NULL
161  * @param tc scheduler context
162  */
163 void
164 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
165 {
166   res = 1;
167   cleanup ();
168   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
169 }
170
171
172 /**
173  * Terminate the test case (success).
174  *
175  * @param cls NULL
176  * @param tc scheduler context
177  */
178 void
179 end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
180 {
181   res = 0;
182   cleanup ();
183   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n");
184 }
185
186
187 /**
188  * Finish the test case (successfully).
189  */
190 void
191 end ()
192 {
193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
194
195   if (end_badly_task != NULL)
196   {
197     GNUNET_SCHEDULER_cancel (end_badly_task);
198     end_badly_task = NULL;
199   }
200   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
201                                 &end_normally, NULL);
202 }
203
204
205 void
206 master_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
207 {
208   GNUNET_assert (NULL != msg);
209   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
210               "Test #%d: Master got PSYC message fragment of size %u "
211               "belonging to message ID %" PRIu64 " with flags %x\n",
212               test, ntohs (msg->header.size),
213               GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
214   // FIXME
215 }
216
217
218 void
219 master_message_part_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg,
220                         const struct GNUNET_MessageHeader *pmsg)
221 {
222   GNUNET_assert (NULL != msg && NULL != pmsg);
223
224   uint64_t message_id = GNUNET_ntohll (msg->message_id);
225   uint32_t flags = ntohl (msg->flags);
226
227   uint16_t type = ntohs (pmsg->type);
228   uint16_t size = ntohs (pmsg->size);
229
230   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
231               "Test #%d: Master got message part of type %u and size %u "
232               "belonging to message ID %" PRIu64 " with flags %x\n",
233               test, type, size, message_id, flags);
234
235   switch (test)
236   {
237   case TEST_SLAVE_TRANSMIT:
238     if (GNUNET_PSYC_MESSAGE_REQUEST != flags)
239     {
240       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241                   "Test #%d: Unexpected request flags: %x" PRIu32 "\n",
242                   test, flags);
243       GNUNET_assert (0);
244       return;
245     }
246     // FIXME: check rest of message
247
248     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
249       master_transmit ();
250     break;
251
252   case TEST_MASTER_TRANSMIT:
253     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
254       master_history_replay_latest ();
255     break;
256
257   case TEST_MASTER_HISTORY_REPLAY:
258   case TEST_MASTER_HISTORY_REPLAY_LATEST:
259     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
260     {
261       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
263                   test, flags);
264       GNUNET_assert (0);
265       return;
266     }
267     break;
268
269   default:
270     GNUNET_assert (0);
271   }
272 }
273
274
275 void
276 slave_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
277 {
278   GNUNET_assert (NULL != msg);
279   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
280               "Test #%d: Slave got PSYC message fragment of size %u "
281               "belonging to message ID %" PRIu64 " with flags %x\n",
282               test, ntohs (msg->header.size),
283               GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
284   // FIXME
285 }
286
287
288 void
289 slave_message_part_cb (void *cls,
290                        const struct GNUNET_PSYC_MessageHeader *msg,
291                        const struct GNUNET_MessageHeader *pmsg)
292 {
293   GNUNET_assert (NULL != msg && NULL != pmsg);
294
295   uint64_t message_id = GNUNET_ntohll (msg->message_id);
296   uint32_t flags = ntohl (msg->flags);
297
298   uint16_t type = ntohs (pmsg->type);
299   uint16_t size = ntohs (pmsg->size);
300
301   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
302               "Test #%d: Slave got message part of type %u and size %u "
303               "belonging to message ID %" PRIu64 " with flags %x\n",
304               test, type, size, message_id, flags);
305
306   switch (test)
307   {
308   case TEST_MASTER_TRANSMIT:
309     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
310       master_history_replay_latest ();
311     break;
312
313   case TEST_SLAVE_HISTORY_REPLAY:
314   case TEST_SLAVE_HISTORY_REPLAY_LATEST:
315     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
316     {
317       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
319                   test, flags);
320       GNUNET_assert (0);
321       return;
322     }
323     break;
324
325   default:
326     GNUNET_assert (0);
327   }
328 }
329
330
331 void
332 state_get_var (void *cls, const struct GNUNET_MessageHeader *mod,
333                const char *name, const void *value,
334                uint32_t value_size, uint32_t full_value_size)
335 {
336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337               "Got state var: %s\n%.*s\n", name, value_size, value);
338 }
339
340
341 /*** Slave state_get_prefix() ***/
342
343 void
344 slave_state_get_prefix_result (void *cls, int64_t result,
345                                const void *err_msg, uint16_t err_msg_size)
346 {
347   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
348               "slave_state_get_prefix:\t%" PRId64 " (%.s)\n",
349               result, err_msg_size, err_msg);
350   // FIXME: GNUNET_assert (2 == result);
351   end ();
352 }
353
354
355 void
356 slave_state_get_prefix ()
357 {
358   test = TEST_SLAVE_STATE_GET_PREFIX;
359   GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", state_get_var,
360                                         slave_state_get_prefix_result, NULL);
361 }
362
363
364 /*** Master state_get_prefix() ***/
365
366
367 void
368 master_state_get_prefix_result (void *cls, int64_t result,
369                                 const void *err_msg, uint16_t err_msg_size)
370 {
371   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372               "master_state_get_prefix:\t%" PRId64 " (%s)\n", result, err_msg);
373   // FIXME: GNUNET_assert (2 == result);
374   slave_state_get_prefix ();
375 }
376
377
378 void
379 master_state_get_prefix ()
380 {
381   test = TEST_MASTER_STATE_GET_PREFIX;
382   GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", state_get_var,
383                                         master_state_get_prefix_result, NULL);
384 }
385
386
387 /*** Slave state_get() ***/
388
389
390 void
391 slave_state_get_result (void *cls, int64_t result,
392                         const void *err_msg, uint16_t err_msg_size)
393 {
394   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
395               "slave_state_get:\t%" PRId64 " (%.*s)\n",
396               result, err_msg_size, err_msg);
397   // FIXME: GNUNET_assert (2 == result);
398   master_state_get_prefix ();
399 }
400
401
402 void
403 slave_state_get ()
404 {
405   test = TEST_SLAVE_STATE_GET;
406   GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", state_get_var,
407                                  slave_state_get_result, NULL);
408 }
409
410
411 /*** Master state_get() ***/
412
413
414 void
415 master_state_get_result (void *cls, int64_t result,
416                          const void *err_msg, uint16_t err_msg_size)
417 {
418   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
419               "master_state_get:\t%" PRId64 " (%.*s)\n",
420               result, err_msg_size, err_msg);
421   // FIXME: GNUNET_assert (1 == result);
422   slave_state_get ();
423 }
424
425
426 void
427 master_state_get ()
428 {
429   test = TEST_MASTER_STATE_GET;
430   GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", state_get_var,
431                                  master_state_get_result, NULL);
432 }
433
434
435 /*** Slave history_replay() ***/
436
437 void
438 slave_history_replay_result (void *cls, int64_t result,
439                              const void *err_msg, uint16_t err_msg_size)
440 {
441   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
442               "slave_history_replay:\t%" PRId64 " (%.*s)\n",
443               result, err_msg_size, err_msg);
444   GNUNET_assert (9 == result);
445
446   master_state_get ();
447 }
448
449
450 void
451 slave_history_replay ()
452 {
453   test = TEST_SLAVE_HISTORY_REPLAY;
454   GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "",
455                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
456                                       slave_message_cb,
457                                       slave_message_part_cb,
458                                       slave_history_replay_result, NULL);
459 }
460
461
462 /*** Master history_replay() ***/
463
464
465 void
466 master_history_replay_result (void *cls, int64_t result,
467                               const void *err_msg, uint16_t err_msg_size)
468 {
469   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
470               "master_history_replay:\t%" PRId64 " (%.*s)\n",
471               result, err_msg_size, err_msg);
472   GNUNET_assert (9 == result);
473
474   slave_history_replay ();
475 }
476
477
478 void
479 master_history_replay ()
480 {
481   test = TEST_MASTER_HISTORY_REPLAY;
482   GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "",
483                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
484                                       master_message_cb,
485                                       master_message_part_cb,
486                                       master_history_replay_result, NULL);
487 }
488
489
490 /*** Slave history_replay_latest() ***/
491
492
493 void
494 slave_history_replay_latest_result (void *cls, int64_t result,
495                                     const void *err_msg, uint16_t err_msg_size)
496 {
497   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
498               "slave_history_replay_latest:\t%" PRId64 " (%.*s)\n",
499               result, err_msg_size, err_msg);
500   GNUNET_assert (9 == result);
501
502   master_history_replay ();
503 }
504
505
506 void
507 slave_history_replay_latest ()
508 {
509   test = TEST_SLAVE_HISTORY_REPLAY_LATEST;
510   GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "",
511                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
512                                              &slave_message_cb,
513                                              &slave_message_part_cb,
514                                              &slave_history_replay_latest_result,
515                                              NULL);
516 }
517
518
519 /*** Master history_replay_latest() ***/
520
521
522 void
523 master_history_replay_latest_result (void *cls, int64_t result,
524                                      const void *err_msg, uint16_t err_msg_size)
525 {
526   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
527               "master_history_replay_latest:\t%" PRId64 " (%.*s)\n",
528               result, err_msg_size, err_msg);
529   GNUNET_assert (9 == result);
530
531   slave_history_replay_latest ();
532 }
533
534
535 void
536 master_history_replay_latest ()
537 {
538   test = TEST_MASTER_HISTORY_REPLAY_LATEST;
539   GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "",
540                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
541                                              &master_message_cb,
542                                              &master_message_part_cb,
543                                              &master_history_replay_latest_result,
544                                              NULL);
545 }
546
547
548 void
549 transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
550 {
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
552   struct TransmitClosure *tmit = cls;
553   if (NULL != tmit->mst_tmit)
554     GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit);
555   else
556     GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit);
557 }
558
559
560 int
561 tmit_notify_data (void *cls, uint16_t *data_size, void *data)
562 {
563   struct TransmitClosure *tmit = cls;
564   if (0 == tmit->data_count)
565   {
566     *data_size = 0;
567     return GNUNET_YES;
568   }
569
570   uint16_t size = strlen (tmit->data[tmit->n]);
571   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572               "Test #%d: Transmit notify data: %u bytes available, "
573               "processing fragment %u/%u (size %u).\n",
574               test, *data_size, tmit->n + 1, tmit->data_count, size);
575   if (*data_size < size)
576   {
577     *data_size = 0;
578     GNUNET_assert (0);
579     return GNUNET_SYSERR;
580   }
581
582   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
583   {
584     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
585                 "Test #%d: Transmission paused.\n", test);
586     tmit->paused = GNUNET_YES;
587     GNUNET_SCHEDULER_add_delayed (
588       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
589                                      tmit->data_delay[tmit->n]),
590       &transmit_resume, tmit);
591     *data_size = 0;
592     return GNUNET_NO;
593   }
594   tmit->paused = GNUNET_NO;
595
596   *data_size = size;
597   memcpy (data, tmit->data[tmit->n], size);
598
599   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
600 }
601
602
603 int
604 tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
605                  uint32_t *full_value_size)
606 {
607   struct TransmitClosure *tmit = cls;
608   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609               "Test #%d: Transmit notify modifier: %lu bytes available, "
610               "%u modifiers left to process.\n",
611               test, *data_size, GNUNET_PSYC_env_get_count (tmit->env));
612
613   uint16_t name_size = 0;
614   size_t value_size = 0;
615   const char *value = NULL;
616
617   if (NULL != oper && NULL != tmit->mod)
618   { /* New modifier */
619     tmit->mod = tmit->mod->next;
620     if (NULL == tmit->mod)
621     { /* No more modifiers, continue with data */
622       *data_size = 0;
623       return GNUNET_YES;
624     }
625
626     GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
627     *full_value_size = tmit->mod->value_size;
628     *oper = tmit->mod->oper;
629     name_size = strlen (tmit->mod->name);
630
631     if (name_size + 1 + tmit->mod->value_size <= *data_size)
632     {
633       *data_size = name_size + 1 + tmit->mod->value_size;
634     }
635     else
636     {
637       tmit->mod_value_size = tmit->mod->value_size;
638       value_size = *data_size - name_size - 1;
639       tmit->mod_value_size -= value_size;
640       tmit->mod_value = tmit->mod->value + value_size;
641     }
642
643     memcpy (data, tmit->mod->name, name_size);
644     ((char *)data)[name_size] = '\0';
645     memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size);
646   }
647   else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
648   { /* Modifier continuation */
649     value = tmit->mod_value;
650     if (tmit->mod_value_size <= *data_size)
651     {
652       value_size = tmit->mod_value_size;
653       tmit->mod_value = NULL;
654     }
655     else
656     {
657       value_size = *data_size;
658       tmit->mod_value += value_size;
659     }
660     tmit->mod_value_size -= value_size;
661
662     if (*data_size < value_size)
663     {
664       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665                   "value larger than buffer: %u < %zu\n",
666                   *data_size, value_size);
667       *data_size = 0;
668       return GNUNET_NO;
669     }
670
671     *data_size = value_size;
672     memcpy (data, value, value_size);
673   }
674
675   return GNUNET_NO;
676 }
677
678
679 static void
680 slave_join ();
681
682
683 void
684 slave_transmit ()
685 {
686   test = TEST_SLAVE_TRANSMIT;
687   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
688               "Test #%d: Slave sending request to master.\n", test);
689
690   tmit = GNUNET_new (struct TransmitClosure);
691   tmit->env = GNUNET_PSYC_env_create ();
692   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
693                               "_abc", "abc def", 7);
694   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
695                               "_abc_def", "abc def ghi", 11);
696   tmit->mod = GNUNET_PSYC_env_head (tmit->env);
697   tmit->n = 0;
698   tmit->data[0] = "slave test";
699   tmit->data_count = 1;
700   tmit->slv_tmit
701     = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod,
702                                   &tmit_notify_data, tmit,
703                                   GNUNET_PSYC_SLAVE_TRANSMIT_NONE);
704 }
705
706
707 void
708 slave_remove_cb (void *cls, int64_t result,
709                  const void *err_msg, uint16_t err_msg_size)
710 {
711   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
712               "slave_remove:\t%" PRId64 " (%.*s)\n",
713               result, err_msg_size, err_msg);
714
715   slave_transmit ();
716 }
717
718
719 void
720 slave_remove ()
721 {
722   test = TEST_SLAVE_REMOVE;
723   struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
724   GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2,
725                                     &slave_remove_cb, chn);
726 }
727
728
729 void
730 slave_add_cb (void *cls, int64_t result,
731               const void *err_msg, uint16_t err_msg_size)
732 {
733   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
734               "slave_add:\t%" PRId64 " (%.*s)\n",
735               result, err_msg_size, err_msg);
736   slave_remove ();
737 }
738
739
740 void
741 slave_add ()
742 {
743   test = TEST_SLAVE_ADD;
744   struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
745   GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn);
746 }
747
748
749 void first_slave_parted (void *cls)
750 {
751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First slave parted.\n");
752   slave_join (TEST_SLAVE_JOIN_ACCEPT);
753 }
754
755
756 void
757 schedule_slave_part (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
758 {
759   GNUNET_PSYC_slave_part (slv, GNUNET_NO, first_slave_parted, NULL);
760 }
761
762
763 static void
764 join_decision_cb (void *cls,
765                   const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
766                   int is_admitted,
767                   const struct GNUNET_PSYC_Message *join_msg)
768 {
769   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
770               "Test #%d: Slave got join decision: %d\n", test, is_admitted);
771
772   switch (test)
773   {
774   case TEST_SLAVE_JOIN_REJECT:
775     GNUNET_assert (0 == is_admitted);
776     GNUNET_assert (1 == join_req_count);
777     GNUNET_SCHEDULER_add_now (schedule_slave_part, NULL);
778     break;
779
780   case TEST_SLAVE_JOIN_ACCEPT:
781     GNUNET_assert (1 == is_admitted);
782     GNUNET_assert (2 == join_req_count);
783     slave_add ();
784     break;
785
786   default:
787     GNUNET_break (0);
788   }
789 }
790
791
792 static void
793 join_request_cb (void *cls,
794                  const struct GNUNET_PSYC_JoinRequestMessage *req,
795                  const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
796                  const struct GNUNET_PSYC_Message *join_msg,
797                  struct GNUNET_PSYC_JoinHandle *jh)
798 {
799   struct GNUNET_HashCode slave_key_hash;
800   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
801   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
802               "Test #%d: Got join request #%u from %s.\n",
803               test, join_req_count, GNUNET_h2s (&slave_key_hash));
804
805   /* Reject first request */
806   int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO;
807   GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL);
808 }
809
810
811 static void
812 slave_connect_cb (void *cls, int result, uint64_t max_message_id)
813 {
814   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
815               "Test #%d: Slave connected: %d, max_message_id: %" PRIu64 "\n",
816               test, result, max_message_id);
817   GNUNET_assert (TEST_SLAVE_JOIN_REJECT == test || TEST_SLAVE_JOIN_ACCEPT == test);
818   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
819 }
820
821
822 static void
823 slave_join (int t)
824 {
825   test = t;
826   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test #%d: Joining slave.\n");
827
828   struct GNUNET_PeerIdentity origin = this_peer;
829   struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
830   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
831                               "_foo", "bar baz", 7);
832   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
833                               "_foo_bar", "foo bar baz", 11);
834   struct GNUNET_PSYC_Message *
835     join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9);
836
837   slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key,
838                                 GNUNET_PSYC_SLAVE_JOIN_NONE,
839                                 &origin, 0, NULL,
840                                 &slave_message_cb, &slave_message_part_cb,
841                                 &slave_connect_cb, &join_decision_cb, NULL,
842                                 join_msg);
843   GNUNET_free (join_msg);
844   slv_chn = GNUNET_PSYC_slave_get_channel (slv);
845   GNUNET_PSYC_env_destroy (env);
846 }
847
848
849 void
850 master_transmit ()
851 {
852   test = TEST_MASTER_TRANSMIT;
853   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
854               "Test #%d: Master sending message to all.\n", test);
855   end_count = 0;
856
857   uint32_t i, j;
858
859   char *name_max = "_test_max";
860   uint8_t name_max_size = sizeof ("_test_max");
861   char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD);
862   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++)
863     val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.';
864
865   char *name_cont = "_test_cont";
866   uint8_t name_cont_size = sizeof ("_test_cont");
867   char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
868                                   + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
869   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++)
870     val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':';
871   for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++)
872     val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!';
873
874   tmit = GNUNET_new (struct TransmitClosure);
875   tmit->env = GNUNET_PSYC_env_create ();
876   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
877                               "_foo", "bar baz", 7);
878   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
879                               name_max, val_max,
880                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
881                               - name_max_size);
882   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
883                               "_foo_bar", "foo bar baz", 11);
884   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
885                               name_cont, val_cont,
886                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size
887                               + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
888   tmit->mod = GNUNET_PSYC_env_head (tmit->env);
889   tmit->data[0] = "foo";
890   tmit->data[1] =  GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1);
891   for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++)
892     tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
893   tmit->data[2] = "foo bar";
894   tmit->data[3] = "foo bar baz";
895   tmit->data_delay[1] = 3;
896   tmit->data_count = 4;
897   tmit->mst_tmit
898     = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod,
899                                    &tmit_notify_data, tmit,
900                                    GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
901 }
902
903
904 void
905 master_start_cb (void *cls, int result, uint64_t max_message_id)
906 {
907   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908               "Test #%d: Master started: %d, max_message_id: %" PRIu64 "\n",
909               test, result, max_message_id);
910   GNUNET_assert (TEST_MASTER_START == test);
911   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
912   slave_join (TEST_SLAVE_JOIN_REJECT);
913 }
914
915
916 void
917 master_start ()
918 {
919   test = TEST_MASTER_START;
920   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test #%d: Starting master.\n", test);
921   mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
922                                   &master_start_cb, &join_request_cb,
923                                   &master_message_cb, &master_message_part_cb,
924                                   NULL);
925   mst_chn = GNUNET_PSYC_master_get_channel (mst);
926 }
927
928 void
929 schedule_master_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
930 {
931   master_start ();
932 }
933
934
935 void
936 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
937 {
938   this_peer = *my_identity;
939
940 #if DEBUG_TEST_PSYC
941   master_start ();
942 #else
943   /* Allow some time for the services to initialize. */
944   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
945                                 &schedule_master_start, NULL);
946 #endif
947
948 }
949
950 /**
951  * Main function of the test, run from scheduler.
952  *
953  * @param cls NULL
954  * @param cfg configuration we use (also to connect to PSYC service)
955  * @param peer handle to access more of the peer (not used)
956  */
957 void
958 #if DEBUG_TEST_PSYC
959 run (void *cls, char *const *args, const char *cfgfile,
960      const struct GNUNET_CONFIGURATION_Handle *c)
961 #else
962 run (void *cls,
963      const struct GNUNET_CONFIGURATION_Handle *c,
964      struct GNUNET_TESTING_Peer *peer)
965 #endif
966 {
967   cfg = c;
968   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
969
970   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
971   slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
972
973   GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
974   GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
975
976   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
977                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
978 }
979
980
981 int
982 main (int argc, char *argv[])
983 {
984   res = 1;
985 #if DEBUG_TEST_PSYC
986   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
987     GNUNET_GETOPT_OPTION_END
988   };
989   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
990                                        "test-psyc [options]",
991                                        opts, &run, NULL))
992     return 1;
993 #else
994   if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
995     return 1;
996 #endif
997   return res;
998 }
999
1000 /* end of test_psyc.c */