e420a50220835de80618f0d485eccfa67ae61afe
[oweals/gnunet.git] / src / hostlist / test_gnunet_daemon_hostlist_learning.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2009, 2010, 2011, 2012, 2016 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  * @file hostlist/test_gnunet_daemon_hostlist_learning.c
20  * @brief test for gnunet_daemon_hostslist.c
21  * @author Christian Grothoff
22  */
23 #include "platform.h"
24 #include "gnunet_util_lib.h"
25 #include "gnunet_arm_service.h"
26 #include "gnunet_core_service.h"
27 #include "gnunet_transport_service.h"
28 #include "gnunet_resolver_service.h"
29 #include "gnunet_statistics_service.h"
30
31 #define MAX_URL_LEN 1000
32
33 /**
34  * How long until wait until testcases fails
35  */
36 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
37
38 #define CHECK_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
39
40
41 struct PeerContext
42 {
43   struct GNUNET_CONFIGURATION_Handle *cfg;
44   struct GNUNET_MessageHeader *hello;
45   struct GNUNET_CORE_Handle *core;
46   struct GNUNET_STATISTICS_Handle *stats;
47   struct GNUNET_OS_Process *arm_proc;
48 };
49
50 static int timeout;
51
52 static int adv_sent;
53
54 static int adv_arrived;
55
56 static int learned_hostlist_saved;
57
58 static int learned_hostlist_downloaded;
59
60 static char *current_adv_uri;
61
62 static const struct GNUNET_CONFIGURATION_Handle *cfg;
63
64 static struct GNUNET_SCHEDULER_Task *timeout_task;
65
66 static struct GNUNET_SCHEDULER_Task *check_task;
67
68 static struct PeerContext adv_peer;
69
70 static struct PeerContext learn_peer;
71
72 static struct GNUNET_STATISTICS_GetHandle *download_stats;
73
74 static struct GNUNET_STATISTICS_GetHandle *urisrecv_stat;
75
76 static struct GNUNET_STATISTICS_GetHandle *advsent_stat;
77
78
79 static void
80 shutdown_testcase ()
81 {
82   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83               "Shutdown testcase....\n");
84   if (NULL != timeout_task)
85   {
86     GNUNET_SCHEDULER_cancel (timeout_task);
87     timeout_task = NULL;
88   }
89   if (NULL != download_stats)
90   {
91     GNUNET_STATISTICS_get_cancel (download_stats);
92     download_stats = NULL;
93   }
94   if (NULL != urisrecv_stat)
95   {
96     GNUNET_STATISTICS_get_cancel (urisrecv_stat);
97     urisrecv_stat = NULL;
98   }
99   if (NULL != advsent_stat)
100   {
101     GNUNET_STATISTICS_get_cancel (advsent_stat);
102     advsent_stat = NULL;
103   }
104   if (NULL != adv_peer.stats)
105   {
106     GNUNET_STATISTICS_destroy (adv_peer.stats, GNUNET_NO);
107     adv_peer.stats = NULL;
108   }
109   if (NULL != learn_peer.stats)
110   {
111     GNUNET_STATISTICS_destroy (learn_peer.stats, GNUNET_NO);
112     learn_peer.stats = NULL;
113   }
114   if (NULL != check_task)
115   {
116     GNUNET_SCHEDULER_cancel (check_task);
117     check_task = NULL;
118   }
119   if (NULL != current_adv_uri)
120   {
121     GNUNET_free (current_adv_uri);
122     current_adv_uri = NULL;
123   }
124   if (NULL != adv_peer.core)
125   {
126     GNUNET_CORE_disconnect (adv_peer.core);
127     adv_peer.core = NULL;
128   }
129   if (NULL != learn_peer.core)
130   {
131     GNUNET_CORE_disconnect (learn_peer.core);
132     learn_peer.core = NULL;
133   }
134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
135               "Killing hostlist server ARM process.\n");
136   if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc,
137                                    GNUNET_TERM_SIG))
138     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
139                          "kill");
140   if (GNUNET_OK !=
141       GNUNET_OS_process_wait (adv_peer.arm_proc))
142     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
143                          "waitpid");
144   GNUNET_OS_process_destroy (adv_peer.arm_proc);
145   adv_peer.arm_proc = NULL;
146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147               "Killing hostlist client ARM process.\n");
148   if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc,
149                                    GNUNET_TERM_SIG))
150     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
151                          "kill");
152   if (GNUNET_OK !=
153       GNUNET_OS_process_wait (learn_peer.arm_proc))
154     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
155                          "waitpid");
156   GNUNET_OS_process_destroy (learn_peer.arm_proc);
157   learn_peer.arm_proc = NULL;
158   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159               "Shutdown complete....\n");
160 }
161
162
163 /**
164  * Timeout, give up.
165  */
166 static void
167 timeout_error (void *cls)
168 {
169   timeout_task = NULL;
170   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171               "Timeout while executing testcase, test failed.\n");
172   timeout = GNUNET_YES;
173   shutdown_testcase ();
174 }
175
176
177 static void
178 process_downloads_done (void *cls, int success)
179 {
180   download_stats = NULL;
181 }
182
183
184 static void
185 do_shutdown (void *cls)
186 {
187   shutdown_testcase ();
188 }
189
190
191 static int
192 process_downloads (void *cls,
193                    const char *subsystem,
194                    const char *name,
195                    uint64_t value,
196                    int is_persistent)
197 {
198   if ( (value >= 2) &&
199        (GNUNET_NO == learned_hostlist_downloaded) )
200   {
201     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
202                 "Peer has successfully downloaded advertised URI\n");
203     learned_hostlist_downloaded = GNUNET_YES;
204     if ((learned_hostlist_saved == GNUNET_YES) && (adv_sent == GNUNET_YES))
205     {
206       GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
207     }
208   }
209   return GNUNET_OK;
210 }
211
212
213 static void
214 process_uris_recv_done (void *cls, int success)
215 {
216   urisrecv_stat = NULL;
217 }
218
219
220 static int
221 process_uris_recv (void *cls,
222                    const char *subsystem,
223                    const char *name,
224                    uint64_t value,
225                    int is_persistent)
226 {
227   struct PeerContext *pc = cls;
228   if ( (pc == &learn_peer) &&
229        (value == 1) &&
230        (learned_hostlist_saved == GNUNET_NO) )
231   {
232     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
233                 "Peer has successfully saved advertised URI\n");
234     learned_hostlist_saved = GNUNET_YES;
235     if ( (learned_hostlist_downloaded == GNUNET_YES) &&
236          (adv_sent == GNUNET_YES) )
237     {
238       GNUNET_SCHEDULER_add_now (&do_shutdown,
239                                 NULL);
240     }
241   }
242   return GNUNET_OK;
243 }
244
245
246 static void
247 process_adv_sent_done (void *cls, int success)
248 {
249   advsent_stat = NULL;
250 }
251
252
253 static int
254 process_adv_sent (void *cls,
255                   const char *subsystem,
256                   const char *name,
257                   uint64_t value,
258                   int is_persistent)
259 {
260   if ((value >= 1) && (adv_sent == GNUNET_NO))
261   {
262     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
263                 "Server has successfully sent advertisement\n");
264     adv_sent = GNUNET_YES;
265     if ((learned_hostlist_downloaded == GNUNET_YES) &&
266         (learned_hostlist_saved == GNUNET_YES))
267     {
268       GNUNET_SCHEDULER_add_now (&do_shutdown,
269                                 NULL);
270     }
271   }
272   return GNUNET_OK;
273 }
274
275
276 /**
277  * Check the server statistics regularly
278  */
279 static void
280 check_statistics (void *cls)
281 {
282   char *stat;
283
284   check_task = NULL;
285   GNUNET_asprintf (&stat,
286                    gettext_noop ("# advertised URI `%s' downloaded"),
287                    current_adv_uri);
288   if (NULL != learn_peer.stats)
289   {
290     if (NULL != download_stats)
291       GNUNET_STATISTICS_get_cancel (download_stats);
292     download_stats =
293         GNUNET_STATISTICS_get (learn_peer.stats,
294                                "hostlist",
295                                stat,
296                                &process_downloads_done,
297                                &process_downloads,
298                                &learn_peer);
299     if (NULL != urisrecv_stat)
300       GNUNET_STATISTICS_get_cancel (urisrecv_stat);
301     urisrecv_stat =
302         GNUNET_STATISTICS_get (learn_peer.stats, "hostlist",
303                                gettext_noop ("# advertised hostlist URIs"),
304                                &process_uris_recv_done, &process_uris_recv,
305                                &learn_peer);
306   }
307   GNUNET_free (stat);
308   if (NULL != adv_peer.stats)
309   {
310     if (NULL != advsent_stat)
311       GNUNET_STATISTICS_get_cancel (advsent_stat);
312     advsent_stat =
313         GNUNET_STATISTICS_get (adv_peer.stats, "hostlist",
314                                gettext_noop ("# hostlist advertisements send"),
315                                &process_adv_sent_done,
316                                &process_adv_sent,
317                                NULL);
318   }
319   check_task =
320       GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL,
321                                     &check_statistics,
322                                     NULL);
323 }
324
325
326 static int
327 check_ad_arrive (void *cls,
328                  const struct GNUNET_MessageHeader *message)
329 {
330   const char *end = (const char *) &message[1];
331   if ('\0' != end[ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - 1])
332   {
333     GNUNET_break (0);
334     return GNUNET_SYSERR;
335   }
336   return GNUNET_OK;
337 }
338
339
340 static void
341 handle_ad_arrive (void *cls,
342                    const struct GNUNET_MessageHeader *message)
343 {
344   char *hostname;
345   char *expected_uri;
346   unsigned long long port;
347   const char *end;
348
349   if (GNUNET_SYSERR ==
350       GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
351                                              "HOSTLIST",
352                                              "HTTPPORT",
353                                              &port))
354   {
355     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356                 "Could not read advertising server's configuration\n");
357     return;
358   }
359
360   if (GNUNET_SYSERR ==
361       GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg,
362                                              "HOSTLIST",
363                                              "EXTERNAL_DNS_NAME",
364                                              &hostname))
365     hostname = GNUNET_RESOLVER_local_fqdn_get ();
366   GNUNET_asprintf (&expected_uri,
367                    "http://%s:%u/",
368                    hostname != NULL ? hostname : "localhost",
369                    (unsigned int) port);
370   end = (const char *) &message[1];
371   current_adv_uri = GNUNET_strdup (end);
372   if (0 == strcmp (expected_uri,
373                    current_adv_uri))
374   {
375     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
376                 "Received hostlist advertisement with URI `%s' as expected\n",
377                 current_adv_uri);
378     adv_arrived = GNUNET_YES;
379     adv_sent = GNUNET_YES;
380   }
381   else
382     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
383                 "Expected URI `%s' and received URI `%s' differ\n",
384                 expected_uri,
385                 current_adv_uri);
386   GNUNET_free (expected_uri);
387   GNUNET_free_non_null (hostname);
388 }
389
390
391 static void
392 setup_learn_peer (struct PeerContext *p,
393                   const char *cfgname)
394 {
395   struct GNUNET_MQ_MessageHandler learn_handlers[] = {
396     GNUNET_MQ_hd_var_size (ad_arrive,
397                            GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT,
398                            struct GNUNET_MessageHeader,
399                            NULL),
400     GNUNET_MQ_handler_end ()
401   };
402   char *filename;
403   unsigned int result;
404   char *binary;
405
406   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
407   p->cfg = GNUNET_CONFIGURATION_create ();
408   p->arm_proc =
409     GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
410                              NULL, NULL, NULL,
411                              binary,
412                              "gnunet-service-arm",
413                              "-c", cfgname, NULL);
414   GNUNET_assert (GNUNET_OK ==
415                  GNUNET_CONFIGURATION_load (p->cfg,
416                                             cfgname));
417   if (GNUNET_OK ==
418       GNUNET_CONFIGURATION_get_value_string (p->cfg,
419                                              "HOSTLIST",
420                                              "HOSTLISTFILE",
421                                              &filename))
422   {
423     if (GNUNET_YES == GNUNET_DISK_file_test (filename))
424     {
425       result = UNLINK (filename);
426       if (result == 0)
427         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
428                     _("Hostlist file `%s' was removed\n"),
429                     filename);
430     }
431     GNUNET_free (filename);
432   }
433   p->core = GNUNET_CORE_connect (p->cfg,
434                                  NULL,
435                                  NULL,
436                                  NULL,
437                                  NULL,
438                                  learn_handlers);
439   GNUNET_assert (NULL != p->core);
440   p->stats = GNUNET_STATISTICS_create ("hostlist",
441                                        p->cfg);
442   GNUNET_assert (NULL != p->stats);
443   GNUNET_free (binary);
444 }
445
446
447 static void
448 setup_adv_peer (struct PeerContext *p,
449                 const char *cfgname)
450 {
451   char *binary;
452
453   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
454   p->cfg = GNUNET_CONFIGURATION_create ();
455   p->arm_proc =
456     GNUNET_OS_start_process (GNUNET_YES,
457                              GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
458                              NULL, NULL, NULL,
459                              binary,
460                              "gnunet-service-arm",
461                              "-c", cfgname, NULL);
462   GNUNET_assert (GNUNET_OK ==
463                  GNUNET_CONFIGURATION_load (p->cfg,
464                                             cfgname));
465   p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
466   GNUNET_assert (NULL != p->stats);
467   GNUNET_free (binary);
468 }
469
470
471 static void
472 run (void *cls,
473      char *const *args,
474      const char *cfgfile,
475      const struct GNUNET_CONFIGURATION_Handle *c)
476 {
477   timeout = GNUNET_NO;
478   adv_sent = GNUNET_NO;
479
480   adv_arrived = 0;
481   learned_hostlist_saved = GNUNET_NO;
482   learned_hostlist_downloaded = GNUNET_NO;
483
484   cfg = c;
485
486   setup_adv_peer (&adv_peer,
487                   "test_learning_adv_peer.conf");
488   setup_learn_peer (&learn_peer,
489                     "test_learning_learn_peer.conf");
490   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
491                                                &timeout_error,
492                                                NULL);
493   check_task =
494       GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL,
495                                     &check_statistics,
496                                     NULL);
497 }
498
499
500 static int
501 check ()
502 {
503   unsigned int failed;
504
505   char *const argv[] = {
506     "test-gnunet-daemon-hostlist-learning",
507     "-c", "learning_data.conf",
508     NULL
509   };
510   struct GNUNET_GETOPT_CommandLineOption options[] = {
511     GNUNET_GETOPT_OPTION_END
512   };
513
514   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
515                       argv,
516                       "test-gnunet-daemon-hostlist-learning",
517                       "nohelp",
518                       options,
519                       &run,
520                       NULL);
521   failed = GNUNET_NO;
522   if (timeout == GNUNET_YES)
523   {
524     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
525                 "Testcase timeout\n");
526     failed = GNUNET_YES;
527   }
528   if (adv_arrived != GNUNET_YES)
529   {
530     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531                 "Learning peer did not receive advertisement from server\n");
532     failed = GNUNET_YES;
533   }
534   if (learned_hostlist_saved == GNUNET_NO)
535   {
536     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537                 "Advertised hostlist was not saved in datastore\n");
538     failed = GNUNET_YES;
539   }
540   if (learned_hostlist_downloaded == GNUNET_NO)
541   {
542     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
543                 "Advertised hostlist could not be downloaded from server\n");
544     failed = GNUNET_YES;
545   }
546   if (adv_sent == GNUNET_NO)
547   {
548     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549                 "Advertised was not sent from server to client\n");
550     failed = GNUNET_YES;
551   }
552   if (GNUNET_YES == failed)
553     return GNUNET_YES;
554   return GNUNET_NO;
555 }
556
557
558 int
559 main (int argc, char *argv[])
560 {
561   int ret;
562
563   GNUNET_DISK_purge_cfg_dir ("test_learning_learn_peer.conf",
564                              "GNUNET_TEST_HOME");
565   GNUNET_DISK_purge_cfg_dir ("test_learning_adv_peer.conf",
566                              "GNUNET_TEST_HOME");
567   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
568                     "WARNING",
569                     NULL);
570   ret = check ();
571   GNUNET_DISK_purge_cfg_dir ("test_learning_learn_peer.conf",
572                              "GNUNET_TEST_HOME");
573   GNUNET_DISK_purge_cfg_dir ("test_learning_adv_peer.conf",
574                              "GNUNET_TEST_HOME");
575   if (GNUNET_YES ==
576       GNUNET_DISK_file_test ("hostlists_learn_peer.file"))
577   {
578     if (0 == UNLINK ("hostlists_learn_peer.file"))
579       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
580                   "Hostlist file hostlists_learn_peer.file was removed\n");
581   }
582   return ret;
583 }
584
585 /* end of test_gnunet_daemon_hostlist_learning.c */