-fix (C) notices
[oweals/gnunet.git] / src / social / test_social.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  * @file social/test_social.c
22  * @brief Tests for the Social API.
23  * @author Gabor X Toth
24  */
25
26 #include <inttypes.h>
27
28 #include "platform.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_common.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_testing_lib.h"
33 #include "gnunet_psyc_util_lib.h"
34 #include "gnunet_social_service.h"
35 #include "gnunet_core_service.h"
36 #include "gnunet_identity_service.h"
37
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
39
40 #define DATA2ARG(data) data, sizeof (data)
41
42 /**
43  * Return value from 'main'.
44  */
45 int res;
46
47 struct GNUNET_SOCIAL_App *app;
48 const char *app_id = "test";
49
50 /**
51  * Handle for task for timeout termination.
52  */
53 struct GNUNET_SCHEDULER_Task * end_badly_task;
54
55 const struct GNUNET_CONFIGURATION_Handle *cfg;
56
57 struct GNUNET_CORE_Handle *core;
58 struct GNUNET_PeerIdentity this_peer;
59
60 struct GNUNET_IDENTITY_Handle *id;
61
62 const struct GNUNET_SOCIAL_Ego *host_ego;
63 const struct GNUNET_SOCIAL_Ego *guest_ego;
64
65 const char *host_name = "Host One";
66 const char *guest_name = "Guest One";
67
68 struct GNUNET_CRYPTO_EddsaPrivateKey *place_key;
69 struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key;
70
71 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
72 struct GNUNET_HashCode place_pub_hash;
73
74 struct GNUNET_CRYPTO_EcdsaPublicKey guest_pub_key;
75 struct GNUNET_CRYPTO_EcdsaPublicKey host_pub_key;
76
77 struct GNUNET_PSYC_Slicer *host_slicer;
78 struct GNUNET_PSYC_Slicer *guest_slicer;
79
80 struct GNUNET_SOCIAL_Host *hst;
81 struct GNUNET_SOCIAL_Guest *gst;
82
83 struct GNUNET_SOCIAL_Place *hst_plc;
84 struct GNUNET_SOCIAL_Place *gst_plc;
85
86 struct GNUNET_SOCIAL_Nym *nym_eject;
87
88 struct GuestEnterMessage
89 {
90   struct GNUNET_PSYC_Message *msg;
91   const char *method_name;
92   struct GNUNET_PSYC_Environment *env;
93   void *data;
94   uint16_t data_size;
95 } guest_enter_msg;
96
97 struct TransmitClosure
98 {
99   struct GNUNET_SOCIAL_Announcement *host_ann;
100   struct GNUNET_SOCIAL_TalkRequest *guest_talk;
101   struct GNUNET_PSYC_Environment *env;
102   char *data[16];
103   uint8_t data_delay[16];
104   uint8_t data_count;
105   uint8_t paused;
106   uint8_t n;
107 } tmit;
108
109 struct ResultClosure {
110   uint32_t n;
111 } mod_foo_bar_rcls;
112
113 uint8_t join_req_count;
114 struct GNUNET_PSYC_Message *join_resp;
115
116 uint32_t counter;
117
118 uint8_t is_guest_nym_added = GNUNET_NO;
119 uint8_t is_host_reconnected = GNUNET_NO;
120 uint8_t is_guest_reconnected = GNUNET_NO;
121
122 enum
123 {
124   TEST_NONE                         =  0,
125   TEST_HOST_CREATE                  =  1,
126   TEST_HOST_ENTER                   =  2,
127   TEST_GUEST_CREATE                 =  3,
128   TEST_GUEST_ENTER                  =  4,
129   TEST_HOST_ANSWER_DOOR_REFUSE      =  5,
130   TEST_GUEST_RECV_ENTRY_DCSN_REFUSE =  6,
131   TEST_HOST_ANSWER_DOOR_ADMIT       =  7,
132   TEST_GUEST_RECV_ENTRY_DCSN_ADMIT  =  8,
133   TEST_HOST_ANNOUNCE                =  9,
134   TEST_HOST_ANNOUNCE_END            = 10,
135   TEST_HOST_ANNOUNCE2               = 11,
136   TEST_HOST_ANNOUNCE2_END           = 12,
137   TEST_GUEST_TALK                   = 13,
138   TEST_GUEST_HISTORY_REPLAY         = 14,
139   TEST_GUEST_HISTORY_REPLAY_LATEST  = 15,
140   TEST_GUEST_LOOK_AT                = 16,
141   TEST_GUEST_LOOK_FOR               = 17,
142   TEST_GUEST_LEAVE                  = 18,
143   TEST_ZONE_ADD_PLACE               = 19,
144   TEST_GUEST_ENTER_BY_NAME          = 20,
145   TEST_RECONNECT                    = 21,
146   TEST_GUEST_LEAVE2                 = 22,
147   TEST_HOST_LEAVE                   = 23,
148 } test;
149
150
151 static void
152 schedule_guest_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
153
154 static void
155 host_answer_door (void *cls,
156                   struct GNUNET_SOCIAL_Nym *nym,
157                   const char *method_name,
158                   struct GNUNET_PSYC_Environment *env,
159                   size_t data_size,
160                   const void *data);
161
162 static void
163 host_enter ();
164
165 static void
166 guest_init ();
167
168 static void
169 guest_enter ();
170
171 static void
172 guest_enter_by_name ();
173
174 static void
175 guest_talk ();
176
177 static void
178 host_announce2 ();
179
180
181 /**
182  * Clean up all resources used.
183  */
184 static void
185 cleanup ()
186 {
187   if (NULL != core)
188   {
189     GNUNET_CORE_disconnect (core);
190     core = NULL;
191   }
192
193   if (NULL != id)
194   {
195     GNUNET_IDENTITY_disconnect (id);
196     id = NULL;
197   }
198
199   if (NULL != guest_slicer)
200   {
201     GNUNET_PSYC_slicer_destroy (guest_slicer);
202     guest_slicer = NULL;
203   }
204
205   if (NULL != host_slicer)
206   {
207     GNUNET_PSYC_slicer_destroy (host_slicer);
208     host_slicer = NULL;
209   }
210
211   if (NULL != gst)
212   {
213     GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL);
214     gst = NULL;
215     gst_plc = NULL;
216   }
217   if (NULL != hst)
218   {
219     GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL);
220     hst = NULL;
221     hst_plc = NULL;
222   }
223   GNUNET_SOCIAL_app_disconnect (app);
224   GNUNET_SCHEDULER_shutdown ();
225 }
226
227
228 /**
229  * Terminate the test case (failure).
230  *
231  * @param cls NULL
232  * @param tc scheduler context
233  */
234 static void
235 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
236 {
237   res = 1;
238   cleanup ();
239   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
240 }
241
242
243 /**
244  * Terminate the test case (success).
245  *
246  * @param cls NULL
247  * @param tc scheduler context
248  */
249 static void
250 end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
251 {
252   res = 0;
253   cleanup ();
254   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n");
255 }
256
257
258 /**
259  * Finish the test case (successfully).
260  */
261 static void
262 end ()
263 {
264   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
265
266   if (end_badly_task != NULL)
267   {
268     GNUNET_SCHEDULER_cancel (end_badly_task);
269     end_badly_task = NULL;
270   }
271   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
272                                 &end_normally, NULL);
273 }
274
275
276 static void
277 transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
278 {
279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
280   struct TransmitClosure *tmit = cls;
281   if (NULL != tmit->host_ann)
282     GNUNET_SOCIAL_host_announce_resume (tmit->host_ann);
283   else
284     GNUNET_SOCIAL_guest_talk_resume (tmit->guest_talk);
285 }
286
287
288 static int
289 notify_data (void *cls, uint16_t *data_size, void *data)
290 {
291   struct TransmitClosure *tmit = cls;
292   if (NULL != tmit->env)
293   {
294     GNUNET_PSYC_env_destroy (tmit->env);
295     tmit->env = NULL;
296   }
297   if (0 == tmit->data_count)
298   {
299     *data_size = 0;
300     return GNUNET_YES;
301   }
302
303   uint16_t size = strlen (tmit->data[tmit->n]) + 1;
304   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
305               "Transmit notify data: %u bytes available, "
306               "processing fragment %u/%u (size %u).\n",
307               *data_size, tmit->n + 1, tmit->data_count, size);
308   if (*data_size < size)
309   {
310     *data_size = 0;
311     GNUNET_assert (0);
312     return GNUNET_SYSERR;
313   }
314
315   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
316   {
317     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
318     tmit->paused = GNUNET_YES;
319     GNUNET_SCHEDULER_add_delayed (
320       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
321                                      tmit->data_delay[tmit->n]),
322       &transmit_resume, tmit);
323     *data_size = 0;
324     return GNUNET_NO;
325   }
326   tmit->paused = GNUNET_NO;
327
328   *data_size = size;
329   memcpy (data, tmit->data[tmit->n], size);
330
331   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
332 }
333
334
335 static void
336 host_left ()
337 {
338   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
339               "The host has left the place.\n");
340   end ();
341 }
342
343
344 static void
345 schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
346 {
347   test = TEST_HOST_LEAVE;
348   GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL);
349   hst = NULL;
350   hst_plc = NULL;
351 }
352
353
354 static void
355 host_farewell2 (void *cls,
356                const struct GNUNET_SOCIAL_Nym *nym,
357                struct GNUNET_PSYC_Environment *env)
358 {
359   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
360               "Nym left the place again.\n");
361   GNUNET_SCHEDULER_add_now (schedule_host_leave, NULL);
362 }
363
364
365 static void
366 host_reconnected (void *cls, int result,
367               const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
368               uint64_t max_message_id)
369 {
370   place_pub_key = *home_pub_key;
371   GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
372   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
373               "Test #%u: Host reconnected to place %s\n",
374               test, GNUNET_h2s (&place_pub_hash));
375
376   is_host_reconnected = GNUNET_YES;
377   if (GNUNET_YES == is_guest_reconnected)
378   {
379     GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL);
380   }
381 }
382
383
384 static void
385 guest_reconnected (void *cls, int result, uint64_t max_message_id)
386 {
387   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
388               "Test #%u: Guest reconnected to place: %d\n",
389               test, result);
390   GNUNET_assert (0 <= result);
391
392   is_guest_reconnected = GNUNET_YES;
393   if (GNUNET_YES == is_host_reconnected)
394   {
395     GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL);
396   }
397 }
398
399
400 static void
401 app_recv_host (void *cls,
402                struct GNUNET_SOCIAL_HostConnection *hconn,
403                struct GNUNET_SOCIAL_Ego *ego,
404                const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
405                enum GNUNET_SOCIAL_PlaceState place_state)
406 {
407   struct GNUNET_HashCode host_pub_hash;
408   GNUNET_CRYPTO_hash (host_pub_key, sizeof (*host_pub_key), &host_pub_hash);
409
410   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411               "Got app host place notification: %s\n",
412               GNUNET_h2s (&host_pub_hash));
413
414   if (test == TEST_RECONNECT)
415   {
416     if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
417     {
418       hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer, host_reconnected,
419                                                 host_answer_door, host_farewell2, NULL);
420     }
421   }
422 }
423
424
425 static void
426 app_recv_guest (void *cls,
427                 struct GNUNET_SOCIAL_GuestConnection *gconn,
428                 struct GNUNET_SOCIAL_Ego *ego,
429                 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
430                 enum GNUNET_SOCIAL_PlaceState place_state)
431 {
432   struct GNUNET_HashCode guest_pub_hash;
433   GNUNET_CRYPTO_hash (guest_pub_key, sizeof (*guest_pub_key), &guest_pub_hash);
434
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436               "Got app guest place notification: %s\n",
437               GNUNET_h2s (&guest_pub_hash));
438
439   if (test == TEST_RECONNECT)
440   {
441     if (0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
442     {
443       gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
444                                                  guest_slicer, guest_reconnected, NULL);
445     }
446   }
447 }
448
449
450 static void
451 app_recv_ego (void *cls,
452               struct GNUNET_SOCIAL_Ego *ego,
453               const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
454               const char *name)
455 {
456   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
457               "Got app ego notification: %p %s %s\n",
458               ego, name,
459               GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key));
460
461   if (NULL != strstr (name, host_name) && TEST_HOST_CREATE == test)
462   {
463     host_ego = ego;
464     host_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (host_ego));
465     GNUNET_assert (TEST_HOST_CREATE == test);
466     host_enter ();
467   }
468   else if (NULL != strstr (name, guest_name))
469   {
470     guest_ego = ego;
471
472     if (TEST_GUEST_CREATE == test)
473       guest_init ();
474   }
475 }
476
477
478 static void
479 schedule_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
480 {
481   test = TEST_RECONNECT;
482
483   GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL);
484   GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL);
485   hst = NULL;
486   gst = NULL;
487
488   GNUNET_SOCIAL_app_disconnect (app);
489   app = GNUNET_SOCIAL_app_connect (cfg, app_id,
490                                    app_recv_ego,
491                                    app_recv_host,
492                                    app_recv_guest,
493                                    NULL);
494 }
495
496
497 static void
498 host_recv_zone_add_place_result (void *cls, int64_t result,
499                                  const void *data, uint16_t data_size)
500 {
501   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
502               "Test #%u: Zone add place result: %d (%.*s).\n",
503               test, result, data_size, data);
504   GNUNET_assert (GNUNET_YES == result);
505
506   GNUNET_assert (GNUNET_YES == is_guest_nym_added);
507   guest_enter_by_name ();
508 }
509
510
511 static void
512 zone_add_place ()
513 {
514   test = TEST_ZONE_ADD_PLACE;
515   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
516               "Test #%u: Adding place to zone.\n", test);
517
518   GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!",
519                                 &place_pub_key, &this_peer, 1, &this_peer,
520                                 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES),
521                                 host_recv_zone_add_place_result, app);
522 }
523
524
525 static void
526 host_farewell (void *cls,
527                const struct GNUNET_SOCIAL_Nym *nym,
528                struct GNUNET_PSYC_Environment *env)
529 {
530   const struct GNUNET_CRYPTO_EcdsaPublicKey *
531     nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
532
533   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
534   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
535               "Farewell: nym %s (%s) has left the place.\n",
536               GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str);
537   GNUNET_free (str);
538   GNUNET_assert (1 == GNUNET_PSYC_env_get_count (env));
539   if (0 != memcmp (&guest_pub_key, nym_key, sizeof (*nym_key)))
540   {
541     str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&guest_pub_key);
542     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
543                 "Farewell: nym does not match guest: %s\n", str);
544     GNUNET_free (str);
545     GNUNET_assert (0);
546   }
547   zone_add_place ();
548 }
549
550
551 static void
552 guest_left (void *cls)
553 {
554   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
555               "The guest has left the place.\n");
556 }
557
558
559 static void
560 guest_leave()
561 {
562   if (test < TEST_RECONNECT)
563     test = TEST_GUEST_LEAVE;
564   else
565     test = TEST_GUEST_LEAVE2;
566
567   struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
568   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
569                        "_message", DATA2ARG ("Leaving."));
570   GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL);
571   GNUNET_PSYC_env_destroy (env);
572   gst = NULL;
573   gst_plc = NULL;
574 }
575
576
577 static void
578 schedule_guest_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
579 {
580   guest_leave ();
581 }
582
583
584 static void
585 guest_look_for_result (void *cls, int64_t result_code,
586                       const void *data, uint16_t data_size)
587 {
588   struct ResultClosure *rcls = cls;
589   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
590               "guest_look_for_result: %d\n", result_code);
591   GNUNET_assert (GNUNET_OK == result_code);
592   GNUNET_assert (3 == rcls->n);
593   GNUNET_free (rcls);
594   GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
595 }
596
597
598 static void
599 guest_look_for_var (void *cls,
600                    const struct GNUNET_MessageHeader *mod,
601                    const char *name,
602                    const void *value,
603                    uint32_t value_size,
604                    uint32_t full_value_size)
605 {
606   struct ResultClosure *rcls = cls;
607   rcls->n++;
608   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
609               "guest_look_for_var: %s\n%.*s\n",
610               name, value_size, value);
611 }
612
613
614 static void
615 guest_look_for ()
616 {
617   test = TEST_GUEST_LOOK_FOR;
618   struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls));
619   GNUNET_SOCIAL_place_look_for (gst_plc, "_foo", guest_look_for_var, guest_look_for_result, rcls);
620 }
621
622
623 static void
624 guest_look_at_result (void *cls, int64_t result_code,
625                       const void *data, uint16_t data_size)
626 {
627   struct ResultClosure *rcls = cls;
628
629   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
630               "guest_look_at_result: %d\n", result_code);
631   GNUNET_assert (GNUNET_OK == result_code);
632   GNUNET_assert (1 == rcls->n);
633   GNUNET_free (rcls);
634   guest_look_for ();
635 }
636
637
638 static void
639 guest_look_at_var (void *cls,
640                    const struct GNUNET_MessageHeader *mod,
641                    const char *name,
642                    const void *value,
643                    uint32_t value_size,
644                    uint32_t full_value_size)
645 {
646   struct ResultClosure *rcls = cls;
647   rcls->n++;
648
649   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
650               "guest_look_at_var: %s\n%.*s\n",
651               name, value_size, value);
652 }
653
654
655 static void
656 guest_look_at ()
657 {
658   test = TEST_GUEST_LOOK_AT;
659   struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls));
660   GNUNET_SOCIAL_place_look_at (gst_plc, "_foo_bar", guest_look_at_var, guest_look_at_result, rcls);
661 }
662
663
664 static void
665 guest_recv_history_replay_latest_result (void *cls, int64_t result,
666                                          const void *data, uint16_t data_size)
667 {
668   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
669               "Test #%u: Guest received latest history replay result: %" PRId64 "\n"
670               "%.*s\n",
671               test, result, data_size, data);
672   GNUNET_assert (2 == counter); /* message count */
673   GNUNET_assert (7 == result); /* fragment count */
674
675   guest_look_at ();
676 }
677
678
679 static void
680 guest_history_replay_latest ()
681 {
682   test = TEST_GUEST_HISTORY_REPLAY_LATEST;
683   counter = 0;
684   GNUNET_SOCIAL_place_history_replay_latest (gst_plc, 3, "",
685                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
686                                              guest_slicer,
687                                              &guest_recv_history_replay_latest_result,
688                                              NULL);
689 }
690
691
692 static void
693 guest_recv_history_replay_result (void *cls, int64_t result,
694                                   const void *data, uint16_t data_size)
695 {
696   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
697               "Test #%u: Guest received history replay result: %" PRId64 "\n"
698               "%.*s\n",
699               test, result, data_size, data);
700   GNUNET_assert (2 == counter); /* message count */
701   GNUNET_assert (7 == result); /* fragment count */
702
703   guest_history_replay_latest ();
704 }
705
706
707 static void
708 guest_history_replay ()
709 {
710   test = TEST_GUEST_HISTORY_REPLAY;
711   counter = 0;
712   GNUNET_SOCIAL_place_history_replay (gst_plc, 1, 3, "",
713                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
714                                       guest_slicer,
715                                       &guest_recv_history_replay_result,
716                                       NULL);
717 }
718
719
720 static void
721 guest_recv_method (void *cls,
722                   const struct GNUNET_PSYC_MessageMethod *meth,
723                   uint64_t message_id,
724                   uint32_t flags,
725                   const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
726                   const char *method_name)
727 {
728   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
729               "Test #%u: Guest received method for message ID %" PRIu64 ":\n"
730               "%s (flags: %x)\n",
731               test, message_id, method_name, flags);
732   /** @todo FIXME: check message */
733 }
734
735
736 static void
737 guest_recv_modifier (void *cls,
738                      const struct GNUNET_MessageHeader *msg,
739                      uint64_t message_id,
740                      enum GNUNET_PSYC_Operator oper,
741                      const char *name,
742                      const void *value,
743                      uint16_t value_size,
744                      uint16_t full_value_size)
745 {
746   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
747               "Test #%u: Guest received modifier for message ID %" PRIu64 ":\n"
748               "%c%s: %.*s (size: %u)\n",
749               test, message_id, oper, name, value_size, value, value_size);
750   /** @todo FIXME: check modifier */
751 }
752
753 static void
754 guest_recv_mod_foo_bar (void *cls,
755                         const struct GNUNET_MessageHeader *msg,
756                         uint64_t message_id,
757                         enum GNUNET_PSYC_Operator oper,
758                         const char *name,
759                         const void *value,
760                         uint16_t value_size,
761                         uint16_t full_value_size)
762 {
763   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
764               "Test #%u: Guest received modifier matching _foo_bar for message ID %" PRIu64 ":\n"
765               "%c%s: %.*s (size: %u)\n",
766               test, message_id, oper, name, value_size, value, value_size);
767   struct ResultClosure *rc = cls;
768   rc->n++;
769   /** @todo FIXME: check modifier */
770 }
771
772
773 static void
774 guest_recv_data (void *cls,
775                 const struct GNUNET_MessageHeader *msg,
776                 uint64_t message_id,
777                 uint64_t data_offset,
778                 const void *data,
779                 uint16_t data_size)
780 {
781   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
782               "Test #%u: Guest received data for message ID %" PRIu64 ":\n"
783               "%.*s\n",
784               test, message_id, data_size, data);
785   /** @todo FIXME: check data */
786 }
787
788
789 static void
790 guest_recv_eom (void *cls,
791                const struct GNUNET_MessageHeader *msg,
792                uint64_t message_id,
793                uint8_t cancelled)
794 {
795   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
796               "Test #%u: Guest received end of message ID %" PRIu64
797               ", cancelled: %u\n",
798               test, message_id, cancelled);
799
800   switch (test)
801   {
802   case TEST_HOST_ANNOUNCE:
803     test = TEST_HOST_ANNOUNCE_END;
804     break;
805
806   case TEST_HOST_ANNOUNCE_END:
807     host_announce2 ();
808     break;
809
810   case TEST_HOST_ANNOUNCE2:
811     test = TEST_HOST_ANNOUNCE2_END;
812     break;
813
814   case TEST_HOST_ANNOUNCE2_END:
815     guest_talk ();
816     break;
817
818   case TEST_GUEST_HISTORY_REPLAY:
819   case TEST_GUEST_HISTORY_REPLAY_LATEST:
820     counter++;
821     break;
822
823   default:
824     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
825     GNUNET_assert (0);
826   }
827 }
828
829
830 static void
831 host_recv_method (void *cls,
832                   const struct GNUNET_PSYC_MessageMethod *meth,
833                   uint64_t message_id,
834                   uint32_t flags,
835                   const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
836                   const char *method_name)
837 {
838   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
839               "Test #%u: Host received method for message ID %" PRIu64 ":\n"
840               "%s\n",
841               test, message_id, method_name);
842   /** @todo FIXME: check message */
843 }
844
845
846 static void
847 host_recv_modifier (void *cls,
848                     const struct GNUNET_MessageHeader *msg,
849                     uint64_t message_id,
850                     enum GNUNET_PSYC_Operator oper,
851                     const char *name,
852                     const void *value,
853                     uint16_t value_size,
854                     uint16_t full_value_size)
855 {
856   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
857               "Test #%u: Host received modifier for message ID %" PRIu64 ":\n"
858               "%c%s: %.*s\n",
859               test, message_id, oper, name, value_size, value);
860 }
861
862
863 static void
864 host_recv_data (void *cls,
865                 const struct GNUNET_MessageHeader *msg,
866                 uint64_t message_id,
867                 uint64_t data_offset,
868                 const void *data,
869                 uint16_t data_size)
870 {
871   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
872               "Test #%u: Host received data for message ID %" PRIu64 ":\n"
873               "%.*s\n",
874               test, message_id, data_size, data);
875 }
876
877
878 static void
879 host_recv_eom (void *cls,
880                const struct GNUNET_MessageHeader *msg,
881                uint64_t message_id,
882                uint8_t cancelled)
883 {
884   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
885               "Test #%u: Host received end of message ID %" PRIu64
886               ", cancelled: %u\n",
887               test, message_id, cancelled);
888
889   switch (test)
890   {
891   case TEST_HOST_ANNOUNCE:
892     test = TEST_HOST_ANNOUNCE_END;
893     break;
894
895   case TEST_HOST_ANNOUNCE_END:
896     host_announce2 ();
897     break;
898
899   case TEST_HOST_ANNOUNCE2:
900     test = TEST_HOST_ANNOUNCE2_END;
901     break;
902
903   case TEST_HOST_ANNOUNCE2_END:
904     guest_talk ();
905     break;
906
907   case TEST_GUEST_TALK:
908     guest_history_replay ();
909     break;
910
911   default:
912     if (TEST_GUEST_LEAVE <= test)
913       break;
914     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
915     GNUNET_assert (0);
916   }
917 }
918
919
920 static void
921 guest_talk ()
922 {
923   test = TEST_GUEST_TALK;
924
925   tmit = (struct TransmitClosure) {};
926   tmit.env = GNUNET_PSYC_env_create ();
927   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
928                        "_bar_foo", DATA2ARG ("one two three"));
929   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
930                        "_bar_baz", DATA2ARG ("four five"));
931   tmit.data[0] = "zzz xxx yyy";
932   tmit.data[1] = "zyx wvu tsr qpo";
933   tmit.data_delay[1] = 1;
934   tmit.data[2] = "testing ten nine eight";
935   tmit.data_count = 3;
936
937   tmit.guest_talk
938     = GNUNET_SOCIAL_guest_talk (gst, "_message_guest", tmit.env,
939                                 &notify_data, &tmit,
940                                 GNUNET_SOCIAL_TALK_NONE);
941 }
942
943
944 static void
945 host_announce ()
946 {
947   test = TEST_HOST_ANNOUNCE;
948
949   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
950               "Test #%u: Host announcement.\n", test);
951
952   tmit = (struct TransmitClosure) {};
953   tmit.env = GNUNET_PSYC_env_create ();
954   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
955                        "_foo", DATA2ARG ("bar baz"));
956   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
957                        "_foo_bar", DATA2ARG ("foo bar"));
958   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
959                        "_foo_bar_baz", DATA2ARG ("foo bar baz"));
960   tmit.data[0] = "aaa bbb ccc";
961   tmit.data[1] = "abc def ghi jkl";
962   tmit.data_delay[1] = 1;
963   tmit.data[2] = "testing one two three";
964   tmit.data[3] = "four five";
965   tmit.data_count = 4;
966
967   tmit.host_ann
968     = GNUNET_SOCIAL_host_announce (hst, "_message_host", tmit.env,
969                                    &notify_data, &tmit,
970                                    GNUNET_SOCIAL_ANNOUNCE_NONE);
971 }
972
973
974 static void
975 host_announce2 ()
976 {
977   GNUNET_assert (2 == mod_foo_bar_rcls.n);
978   GNUNET_PSYC_slicer_modifier_remove (guest_slicer, "_foo_bar",
979                                       guest_recv_mod_foo_bar);
980
981   test = TEST_HOST_ANNOUNCE2;
982
983   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
984               "Test #%u: Host announcement 2.\n", test);
985
986   tmit = (struct TransmitClosure) {};
987   tmit.env = GNUNET_PSYC_env_create ();
988   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
989                        "_foo2", DATA2ARG ("BAR BAZ"));
990   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
991                        "_foo2_bar", DATA2ARG ("FOO BAR"));
992   GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
993                        "_foo2_bar", DATA2ARG ("FOO BAR BAZ"));
994   tmit.data[0] = "AAA BBB CCC";
995   tmit.data[1] = "ABC DEF GHI JKL";
996   tmit.data[2] = "TESTING ONE TWO THREE";
997   tmit.data_count = 3;
998
999   tmit.host_ann
1000     = GNUNET_SOCIAL_host_announce (hst, "_message_host_two", tmit.env,
1001                                    &notify_data, &tmit,
1002                                    GNUNET_SOCIAL_ANNOUNCE_NONE);
1003 }
1004
1005
1006 static void
1007 guest_recv_entry_decision (void *cls,
1008                            int is_admitted,
1009                            const struct GNUNET_PSYC_Message *entry_msg)
1010 {
1011   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1012               "Test #%u: Guest received entry decision (try %u): %d.\n",
1013               test, join_req_count, is_admitted);
1014
1015   if (NULL != entry_msg)
1016   {
1017     struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
1018     const char *method_name = NULL;
1019     const void *data = NULL;
1020     uint16_t data_size = 0;
1021     struct GNUNET_PSYC_MessageHeader *
1022       pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
1023     GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
1024     GNUNET_free (pmsg);
1025
1026     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1027                 "%s\n%.*s\n",
1028                 method_name, data_size, data);
1029     /** @todo FIXME: check response message */
1030   }
1031
1032   switch (test)
1033   {
1034   case TEST_GUEST_RECV_ENTRY_DCSN_REFUSE:
1035     GNUNET_assert (GNUNET_NO == is_admitted);
1036     guest_enter ();
1037     break;
1038
1039   case TEST_GUEST_RECV_ENTRY_DCSN_ADMIT:
1040     GNUNET_assert (GNUNET_YES == is_admitted);
1041     host_announce ();
1042     break;
1043
1044   case TEST_GUEST_ENTER_BY_NAME:
1045     GNUNET_SCHEDULER_add_now (schedule_reconnect, NULL);
1046     break;
1047
1048   default:
1049     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
1050     GNUNET_assert (0);
1051   }
1052 }
1053
1054
1055 static void
1056 host_answer_door (void *cls,
1057                   struct GNUNET_SOCIAL_Nym *nym,
1058                   const char *method_name,
1059                   struct GNUNET_PSYC_Environment *env,
1060                   size_t data_size,
1061                   const void *data)
1062 {
1063   join_req_count++;
1064
1065   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1066               "Test #%u: Host received entry request from guest (try %u).\n",
1067               test, join_req_count);
1068   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1069               "%s\n%.*s\n",
1070               method_name, data_size, data);
1071
1072   switch (test)
1073   {
1074   case TEST_HOST_ANSWER_DOOR_REFUSE:
1075     test = TEST_GUEST_RECV_ENTRY_DCSN_REFUSE;
1076     join_resp = GNUNET_PSYC_message_create ("_refuse_nym", env,
1077                                             DATA2ARG ("Go away!"));
1078     GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, join_resp);
1079     break;
1080
1081   case TEST_HOST_ANSWER_DOOR_ADMIT:
1082     test = TEST_GUEST_RECV_ENTRY_DCSN_ADMIT;
1083   case TEST_GUEST_ENTER_BY_NAME:
1084     join_resp = GNUNET_PSYC_message_create ("_admit_nym", env,
1085                                             DATA2ARG ("Welcome, nym!"));
1086     GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, join_resp);
1087     break;
1088
1089   default:
1090     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
1091     GNUNET_assert (0);
1092   }
1093 }
1094
1095
1096 static void
1097 guest_recv_local_enter (void *cls, int result, uint64_t max_message_id)
1098 {
1099   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1100               "Test #%u: Guest entered to local place: %d\n",
1101               test, result);
1102   GNUNET_assert (0 <= result);
1103 }
1104
1105
1106 static void
1107 guest_enter ()
1108 {
1109   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1110               "Test #%u: Entering to place as guest.\n", test);
1111
1112   struct GuestEnterMessage *emsg = &guest_enter_msg;
1113
1114   emsg->method_name = "_request_enter";
1115   emsg->env = GNUNET_PSYC_env_create ();
1116   GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1117                        "_abc", "abc def", 7);
1118   GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1119                        "_abc_def", "abc def ghi", 11);
1120   emsg->data = "let me in";
1121   emsg->data_size = strlen (emsg->data) + 1;
1122   emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
1123                                           emsg->data, emsg->data_size);
1124
1125   gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key,
1126                                    GNUNET_PSYC_SLAVE_JOIN_NONE,
1127                                    &this_peer, 0, NULL, emsg->msg, guest_slicer,
1128                                    guest_recv_local_enter,
1129                                    guest_recv_entry_decision, NULL);
1130   gst_plc = GNUNET_SOCIAL_guest_get_place (gst);
1131 }
1132
1133
1134 static void
1135 guest_enter_by_name ()
1136 {
1137   test = TEST_GUEST_ENTER_BY_NAME;
1138   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1139               "Test #%u: Entering to place by name as guest.\n", test);
1140
1141   struct GuestEnterMessage *emsg = &guest_enter_msg;
1142
1143   emsg->method_name = "_request_enter";
1144   emsg->env = GNUNET_PSYC_env_create ();
1145   GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1146                        "_abc", "abc def", 7);
1147   GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1148                        "_abc_def", "abc def ghi", 11);
1149   emsg->data = "let me in";
1150   emsg->data_size = strlen (emsg->data) + 1;
1151   emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
1152                                           emsg->data, emsg->data_size);
1153
1154   gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego,
1155                                            "home.host.gnu", "let.me*in!",
1156                                            emsg->msg, guest_slicer,
1157                                            guest_recv_local_enter,
1158                                            guest_recv_entry_decision, NULL);
1159   gst_plc = GNUNET_SOCIAL_guest_get_place (gst);
1160 }
1161
1162
1163 static void
1164 app_recv_zone_add_nym_result (void *cls, int64_t result,
1165                               const void *data, uint16_t data_size)
1166 {
1167   GNUNET_assert (GNUNET_YES == result);
1168   is_guest_nym_added = GNUNET_YES;
1169 }
1170
1171
1172 static void
1173 guest_init ()
1174 {
1175   guest_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (guest_ego));
1176
1177   guest_slicer = GNUNET_PSYC_slicer_create ();
1178   GNUNET_PSYC_slicer_method_add (guest_slicer, "",
1179                                  guest_recv_method, guest_recv_modifier,
1180                                  guest_recv_data, guest_recv_eom, NULL);
1181   GNUNET_PSYC_slicer_modifier_add (guest_slicer, "_foo_bar",
1182                                    guest_recv_mod_foo_bar, &mod_foo_bar_rcls);
1183   test = TEST_HOST_ANSWER_DOOR_ADMIT;
1184
1185   GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", &host_pub_key,
1186                               GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES),
1187                               app_recv_zone_add_nym_result, NULL);
1188   guest_enter ();
1189 }
1190
1191
1192 static void
1193 id_guest_created (void *cls, const char *emsg)
1194 {
1195   if (NULL != emsg)
1196   {
1197     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1198                 "Could not create guest identity: %s\n", emsg);
1199 #if ! DEBUG_TEST_SOCIAL
1200     GNUNET_assert (0);
1201 #endif
1202   }
1203   if (NULL != guest_ego)
1204     guest_init ();
1205 }
1206
1207
1208 static void
1209 host_entered (void *cls, int result,
1210               const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
1211               uint64_t max_message_id)
1212 {
1213   place_pub_key = *home_pub_key;
1214   GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
1215   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1216               "Host entered to place %s\n", GNUNET_h2s (&place_pub_hash));
1217
1218   test = TEST_GUEST_CREATE;
1219   GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL);
1220 }
1221
1222
1223 static void
1224 host_enter ()
1225 {
1226   host_slicer = GNUNET_PSYC_slicer_create ();
1227   GNUNET_PSYC_slicer_method_add (host_slicer, "",
1228                                  &host_recv_method, &host_recv_modifier,
1229                                  &host_recv_data, &host_recv_eom, NULL);
1230
1231   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Entering to place as host.\n");
1232   test = TEST_HOST_ENTER;
1233   hst = GNUNET_SOCIAL_host_enter (app, host_ego,
1234                                   GNUNET_PSYC_CHANNEL_PRIVATE,
1235                                   host_slicer, host_entered,
1236                                   host_answer_door, host_farewell, NULL);
1237   hst_plc = GNUNET_SOCIAL_host_get_place (hst);
1238 }
1239
1240
1241 static void
1242 id_host_created (void *cls, const char *emsg)
1243 {
1244   if (NULL != core)
1245   {
1246     GNUNET_CORE_disconnect (core);
1247     core = NULL;
1248   }
1249
1250   if (NULL != emsg)
1251   {
1252     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1253                 "Could not create host identity: %s\n", emsg);
1254 #if ! DEBUG_TEST_SOCIAL
1255     GNUNET_assert (0);
1256 #endif
1257   }
1258
1259   app = GNUNET_SOCIAL_app_connect (cfg, app_id,
1260                                    app_recv_ego,
1261                                    app_recv_host,
1262                                    app_recv_guest,
1263                                    NULL);
1264 }
1265
1266
1267 static void
1268 identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego,
1269                  void **ctx, const char *name)
1270 {
1271 }
1272
1273
1274 static void
1275 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1276 {
1277   this_peer = *my_identity;
1278   id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL);
1279
1280   test = TEST_HOST_CREATE;
1281   GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL);
1282 }
1283
1284
1285 /**
1286  * Main function of the test, run from scheduler.
1287  *
1288  * @param cls NULL
1289  * @param cfg configuration we use (also to connect to Social service)
1290  * @param peer handle to access more of the peer (not used)
1291  */
1292 static void
1293 #if DEBUG_TEST_SOCIAL
1294 run (void *cls, char *const *args, const char *cfgfile,
1295      const struct GNUNET_CONFIGURATION_Handle *c)
1296 #else
1297 run (void *cls,
1298      const struct GNUNET_CONFIGURATION_Handle *c,
1299      struct GNUNET_TESTING_Peer *peer)
1300 #endif
1301 {
1302   cfg = c;
1303   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
1304
1305   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
1306                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1307 }
1308
1309
1310 int
1311 main (int argc, char *argv[])
1312 {
1313   res = 1;
1314 #if DEBUG_TEST_SOCIAL
1315   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
1316     GNUNET_GETOPT_OPTION_END
1317   };
1318   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-social",
1319                                        "test-social [options]",
1320                                        opts, &run, NULL))
1321     return 1;
1322 #else
1323   if (0 != GNUNET_TESTING_peer_run ("test-social", "test_social.conf", &run, NULL))
1324     return 1;
1325 #endif
1326   return res;
1327 }
1328
1329 /* end of test_social.c */