add copyright headers, fix includes
[oweals/gnunet.git] / src / sensor / test_gnunet-service-sensor_reporting.c
1   /*
2    * This file is part of GNUnet.
3    * Copyright (C)
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 sensor/test_gnunet-service-sensor_reporting.c
22  * @brief testcase for gnunet-service-sensor_reporting.c
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_testbed_service.h"
27 #include "gnunet_sensor_util_lib.h"
28 #include "sensor.h"
29 #include "gnunet_peerstore_service.h"
30 #include "gnunet_sensor_service.h"
31
32 /**
33  * Number of peers to start for the test
34  */
35 #define NUM_PEERS 2
36
37 /**
38  * Test timeout
39  */
40 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
41
42 /**
43  * How long to wait between starting everything and forcing anomalies to give
44  * the peer enough time to stabilize.
45  */
46 #define ANOMALY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
47
48 /**
49  * Information about a test peer
50  */
51 struct TestPeer
52 {
53
54   /**
55    * DLL
56    */
57   struct TestPeer *prev;
58
59   /**
60    * DLL
61    */
62   struct TestPeer *next;
63
64   /**
65    * TESTBED information about the peer
66    */
67   struct GNUNET_TESTBED_Peer *testbed_peer;
68
69   /**
70    * Peer indentity
71    */
72   struct GNUNET_PeerIdentity peer_id;
73
74   /**
75    * Peerstore watch context for this peer's anomaly reports
76    */
77   struct GNUNET_PEERSTORE_WatchContext *wc;
78
79   /**
80    * TESTBED operation connecting us to sensor service
81    */
82   struct GNUNET_TESTBED_Operation *sensor_op;
83
84   /**
85    * Sensor service handle
86    */
87   struct GNUNET_SENSOR_Handle *sensor;
88
89   /**
90    * GNUNET scheduler task that forces the anomaly after a stabilization delay
91    */
92   struct GNUNET_SCHEDULER_Task * delay_task;
93
94 };
95
96 /**
97  * Test name
98  */
99 static const char *testname = "test_gnunet-service-sensor_reporting";
100
101 /**
102  * Name of GNUNET config file used in this test
103  */
104 static const char *cfg_filename = "test_gnunet-service-sensor_reporting.conf";
105
106 /**
107  * Test sensor name
108  */
109 static const char *sensor_name = "test-sensor-statistics";
110
111 /**
112  * Path to read test sensor from
113  */
114 static const char *sensor_path_src = "test_sensors/test-sensor-statistics";
115
116 /**
117  * Path to write new test sensor to
118  */
119 static const char *sensor_path_dest =
120     "/tmp/test-gnunet-service-sensor-reporting/test-sensor-statistics";
121
122 /**
123  * Head of DLL of peers
124  */
125 static struct TestPeer *peer_head;
126
127 /**
128  * Tail of DLL of peers
129  */
130 static struct TestPeer *peer_tail;
131
132 /**
133  * Number of peers started and got information for
134  */
135 static int started_peers = 0;
136
137 /**
138  * Number of peers reported anomalies with full list of anomalous neighbors
139  */
140 static int reported_peers = 0;
141
142 /**
143  * TESTBED operation connecting us to peerstore service
144  */
145 static struct GNUNET_TESTBED_Operation *peerstore_op;
146
147 /**
148  * Handle to the peerstore service
149  */
150 static struct GNUNET_PEERSTORE_Handle *peerstore;
151
152 /**
153  * Task used to shutdown / expire the test
154  */
155 static struct GNUNET_SCHEDULER_Task * shutdown_task;
156
157 /**
158  * Status of the test to be returned by main()
159  */
160 static int ok = 1;
161
162
163 static void
164 destroy_peer (struct TestPeer *peer)
165 {
166   if (NULL != peer->delay_task)
167   {
168     GNUNET_SCHEDULER_cancel (peer->delay_task);
169     peer->delay_task = NULL;
170   }
171   if (NULL != peer->sensor_op)
172   {
173     GNUNET_TESTBED_operation_done (peer->sensor_op);
174     peer->sensor_op = NULL;
175   }
176   if (NULL != peer->wc)
177   {
178     GNUNET_PEERSTORE_watch_cancel (peer->wc);
179     peer->wc = NULL;
180   }
181   GNUNET_free (peer);
182 }
183
184
185 /**
186  * Shutdown task
187  *
188  * @param cls Closure (unused)
189  * @param tc Task context (unused)
190  */
191 static void
192 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
193 {
194   struct TestPeer *peer;
195
196   peer = peer_head;
197   while (NULL != peer)
198   {
199     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, peer);
200     destroy_peer (peer);
201     peer = peer_head;
202   }
203   if (NULL != peerstore_op)
204   {
205     GNUNET_TESTBED_operation_done (peerstore_op);
206     peerstore_op = NULL;
207   }
208   GNUNET_SCHEDULER_shutdown ();
209 }
210
211
212 /**
213  * Write new temp sensor directory with a sensor updated with collection point
214  * peer id
215  */
216 static void
217 write_new_sensor_dir (struct TestPeer *cp_peer)
218 {
219   struct GNUNET_CONFIGURATION_Handle *sensorcfg;
220
221   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_test (sensor_path_src));
222   sensorcfg = GNUNET_CONFIGURATION_create ();
223   GNUNET_assert (GNUNET_SYSERR !=
224                  GNUNET_CONFIGURATION_parse (sensorcfg, sensor_path_src));
225   GNUNET_CONFIGURATION_set_value_string (sensorcfg, sensor_name,
226                                          "COLLECTION_POINT",
227                                          GNUNET_i2s_full (&cp_peer->peer_id));
228   GNUNET_assert (GNUNET_OK ==
229                  GNUNET_DISK_directory_create_for_file (sensor_path_dest));
230   GNUNET_CONFIGURATION_write (sensorcfg, sensor_path_dest);
231   GNUNET_CONFIGURATION_destroy (sensorcfg);
232 }
233
234
235 /**
236  * Function called by PEERSTORE for each matching record.
237  *
238  * @param cls closure
239  * @param record peerstore record information
240  * @param emsg error message, or NULL if no errors
241  * @return #GNUNET_YES to continue iterating, #GNUNET_NO to stop
242  */
243 static int
244 peerstore_watch_cb (void *cls,
245                     const struct GNUNET_PEERSTORE_Record *record,
246                     const char *emsg)
247 {
248   struct TestPeer *peer = cls;
249   struct GNUNET_SENSOR_DashboardAnomalyEntry *anomaly;
250
251   GNUNET_assert (NULL != record);
252   GNUNET_assert (record->value_size ==
253                  sizeof (struct GNUNET_SENSOR_DashboardAnomalyEntry));
254   anomaly = record->value;
255   GNUNET_assert (0 ==
256                  GNUNET_CRYPTO_cmp_peer_identity (&peer->peer_id,
257                                                   record->peer));
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259               "Peerstore watch got an anomaly report from peer `%s':\n"
260               "Anomalous: %d\n" "Anomalous neigbors: %f.\n",
261               GNUNET_i2s (&peer->peer_id), anomaly->anomalous,
262               anomaly->anomalous_neighbors);
263   if (1 == anomaly->anomalous_neighbors)
264     reported_peers++;
265   if (reported_peers == NUM_PEERS)
266   {
267     ok = 0;
268     GNUNET_SCHEDULER_cancel (shutdown_task);
269     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
270   }
271   return GNUNET_YES;
272 }
273
274
275 /**
276  * Task that pushes fake anomalies to running peers
277  */
278 static void
279 force_anomaly_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
280 {
281   struct TestPeer *peer = cls;
282
283   peer->delay_task = NULL;
284   GNUNET_SENSOR_force_anomaly (peer->sensor, (char *) sensor_name, GNUNET_YES,
285                                NULL, NULL);
286 }
287
288
289 /**
290  * Callback to be called when sensor service connect operation is completed
291  *
292  * @param cls the callback closure from functions generating an operation
293  * @param op the operation that has been finished
294  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
295  * @param emsg error message in case the operation has failed; will be NULL if
296  *          operation has executed successfully.
297  */
298 static void
299 sensor_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
300                    void *ca_result, const char *emsg)
301 {
302   struct TestPeer *peer = cls;
303   struct GNUNET_SENSOR_Handle *sensor = ca_result;
304
305   peer->sensor = sensor;
306   peer->delay_task =
307       GNUNET_SCHEDULER_add_delayed (ANOMALY_DELAY, &force_anomaly_task, peer);
308 }
309
310
311 /**
312  * Adapter function called to establish a connection to sensor service.
313  *
314  * @param cls closure
315  * @param cfg configuration of the peer to connect to; will be available until
316  *          GNUNET_TESTBED_operation_done() is called on the operation returned
317  *          from GNUNET_TESTBED_service_connect()
318  * @return service handle to return in 'op_result', NULL on error
319  */
320 static void *
321 sensor_connect_adapter (void *cls,
322                         const struct GNUNET_CONFIGURATION_Handle *cfg)
323 {
324   struct GNUNET_SENSOR_Handle *sensor;
325
326   sensor = GNUNET_SENSOR_connect (cfg);
327   return sensor;
328 }
329
330
331 /**
332  * Adapter function called to destroy a connection to sensor service.
333  *
334  * @param cls closure
335  * @param op_result service handle returned from the connect adapter
336  */
337 static void
338 sensor_disconnect_adapter (void *cls, void *op_result)
339 {
340   struct GNUNET_SENSOR_Handle *sensor = op_result;
341
342   GNUNET_SENSOR_disconnect (sensor);
343 }
344
345
346 /**
347  * Callback to be called when sensor service is started
348  *
349  * @param cls the callback closure from functions generating an operation
350  * @param op the operation that has been finished
351  * @param emsg error message in case the operation has failed; will be NULL if
352  *          operation has executed successfully.
353  */
354 static void
355 sensor_service_started (void *cls, struct GNUNET_TESTBED_Operation *op,
356                         const char *emsg)
357 {
358   struct TestPeer *peer = cls;
359
360   if (NULL != emsg)
361   {
362     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ERROR: %s.\n", emsg);
363     GNUNET_assert (0);
364   }
365   peer->sensor_op =
366       GNUNET_TESTBED_service_connect (NULL, peer->testbed_peer, "sensor",
367                                       &sensor_connect_cb, peer,
368                                       &sensor_connect_adapter,
369                                       &sensor_disconnect_adapter, NULL);
370   GNUNET_TESTBED_operation_done (op);
371 }
372
373
374 /**
375  * Callback to be called when peerstore service connect operation is completed
376  *
377  * @param cls the callback closure from functions generating an operation
378  * @param op the operation that has been finished
379  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
380  * @param emsg error message in case the operation has failed; will be NULL if
381  *          operation has executed successfully.
382  */
383 static void
384 peerstore_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
385                       void *ca_result, const char *emsg)
386 {
387   struct TestPeer *peer;
388
389   peer = peer_head;
390   while (NULL != peer)
391   {
392     GNUNET_PEERSTORE_watch (peerstore, "sensordashboard-anomalies",
393                             &peer->peer_id, sensor_name, &peerstore_watch_cb,
394                             peer);
395     /* Start sensor service */
396     GNUNET_TESTBED_peer_manage_service (NULL, peer->testbed_peer, "sensor",
397                                         &sensor_service_started, peer, 1);
398     peer = peer->next;
399   }
400 }
401
402
403 /**
404  * Adapter function called to establish a connection to peerstore service.
405  *
406  * @param cls closure
407  * @param cfg configuration of the peer to connect to; will be available until
408  *          GNUNET_TESTBED_operation_done() is called on the operation returned
409  *          from GNUNET_TESTBED_service_connect()
410  * @return service handle to return in 'op_result', NULL on error
411  */
412 static void *
413 peerstore_connect_adapter (void *cls,
414                            const struct GNUNET_CONFIGURATION_Handle *cfg)
415 {
416   peerstore = GNUNET_PEERSTORE_connect (cfg);
417   GNUNET_assert (NULL != peerstore);
418   return peerstore;
419 }
420
421
422 /**
423  * Adapter function called to destroy a connection to peerstore service.
424  *
425  * @param cls closure
426  * @param op_result service handle returned from the connect adapter
427  */
428 static void
429 peerstore_disconnect_adapter (void *cls, void *op_result)
430 {
431   GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
432   peerstore = NULL;
433   peerstore_op = NULL;
434 }
435
436
437 /**
438  * Callback to be called when dashboard service is started
439  *
440  * @param cls the callback closure from functions generating an operation
441  * @param op the operation that has been finished
442  * @param emsg error message in case the operation has failed; will be NULL if
443  *          operation has executed successfully.
444  */
445 static void
446 dashboard_started (void *cls, struct GNUNET_TESTBED_Operation *op,
447                    const char *emsg)
448 {
449   if (NULL != emsg)
450   {
451     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ERROR: %s.\n", emsg);
452     GNUNET_assert (0);
453   }
454   GNUNET_TESTBED_operation_done (op);
455   /* Connect to peerstore service on first peer */
456   peerstore_op =
457       GNUNET_TESTBED_service_connect (NULL, peer_head->testbed_peer,
458                                       "peerstore", &peerstore_connect_cb, NULL,
459                                       &peerstore_connect_adapter,
460                                       &peerstore_disconnect_adapter, NULL);
461 }
462
463
464 /**
465  * Callback to be called when the requested peer information is available
466  *
467  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
468  * @param op the operation this callback corresponds to
469  * @param pinfo the result; will be NULL if the operation has failed
470  * @param emsg error message if the operation has failed; will be NULL if the
471  *          operation is successfull
472  */
473 static void
474 peer_info_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
475               const struct GNUNET_TESTBED_PeerInformation *pinfo,
476               const char *emsg)
477 {
478   struct GNUNET_TESTBED_Peer *testbed_peer = cb_cls;
479   struct TestPeer *peer;
480
481   peer = GNUNET_new (struct TestPeer);
482
483   peer->testbed_peer = testbed_peer;
484   peer->delay_task = NULL;
485   GNUNET_CRYPTO_get_peer_identity (pinfo->result.cfg, &peer->peer_id);
486   if (NULL == peer_head)        /* First peer (collection point) */
487   {
488     /* Rewrite sensor with collection point peer id */
489     write_new_sensor_dir (peer);
490   }
491   GNUNET_CONTAINER_DLL_insert_tail (peer_head, peer_tail, peer);
492   started_peers++;
493   if (NUM_PEERS == started_peers)
494   {
495     /* Start dashboard service on first peer */
496     GNUNET_TESTBED_peer_manage_service (NULL, peer_head->testbed_peer,
497                                         "sensordashboard", &dashboard_started,
498                                         NULL, 1);
499   }
500   GNUNET_TESTBED_operation_done (op);
501 }
502
503
504 /**
505  * Signature of a main function for a testcase.
506  *
507  * @param cls closure
508  * @param h the run handle
509  * @param num_peers number of peers in 'peers'
510  * @param peers handle to peers run in the testbed.  NULL upon timeout (see
511  *          GNUNET_TESTBED_test_run()).
512  * @param links_succeeded the number of overlay link connection attempts that
513  *          succeeded
514  * @param links_failed the number of overlay link connection attempts that
515  *          failed
516  * @see GNUNET_TESTBED_test_run()
517  */
518 static void
519 test_master (void *cls, struct GNUNET_TESTBED_RunHandle *h,
520              unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers,
521              unsigned int links_succeeded, unsigned int links_failed)
522 {
523   int i;
524
525   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526               "%d peers started. %d links succeeded. %d links failed.\n",
527               num_peers, links_succeeded, links_failed);
528   GNUNET_assert (NUM_PEERS == num_peers);
529   GNUNET_assert (0 == links_failed);
530   /* Schedule test timeout */
531   shutdown_task =
532       GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &do_shutdown, NULL);
533   /* Collect peer information */
534   for (i = 0; i < num_peers; i++)
535   {
536     GNUNET_TESTBED_peer_get_information (peers[i],
537                                          GNUNET_TESTBED_PIT_CONFIGURATION,
538                                          &peer_info_cb, peers[i]);
539   }
540 }
541
542
543 int
544 main (int argc, char *argv[])
545 {
546   GNUNET_log_setup (testname, "INFO", NULL);
547   if (GNUNET_OK ==
548       GNUNET_TESTBED_test_run (testname, cfg_filename, NUM_PEERS, 0, NULL, NULL,
549                                &test_master, NULL))
550     return ok;
551   return 1;
552 }