sensor: fixes for proof-of-work, test passes now
[oweals/gnunet.git] / src / sensor / test_gnunet-service-sensor_reporting.c
1   /*
2    * This file is part of GNUnet.
3    * (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., 59 Temple Place - Suite 330,
18    * Boston, MA 02111-1307, 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   GNUNET_SCHEDULER_TaskIdentifier 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 GNUNET_SCHEDULER_TaskIdentifier 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 (GNUNET_SCHEDULER_NO_TASK != peer->delay_task)
167   {
168     GNUNET_SCHEDULER_cancel (peer->delay_task);
169     peer->delay_task = GNUNET_SCHEDULER_NO_TASK;
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, struct GNUNET_PEERSTORE_Record *record,
245                     char *emsg)
246 {
247   struct TestPeer *peer = cls;
248   struct GNUNET_SENSOR_DashboardAnomalyEntry *anomaly;
249
250   GNUNET_assert (NULL != record);
251   GNUNET_assert (record->value_size ==
252                  sizeof (struct GNUNET_SENSOR_DashboardAnomalyEntry));
253   anomaly = record->value;
254   GNUNET_assert (0 ==
255                  GNUNET_CRYPTO_cmp_peer_identity (&peer->peer_id,
256                                                   record->peer));
257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
258               "Peerstore watch got an anomaly report from peer `%s':\n"
259               "Anomalous: %d\n" "Anomalous neigbors: %f.\n",
260               GNUNET_i2s (&peer->peer_id), anomaly->anomalous,
261               anomaly->anomalous_neighbors);
262   if (1 == anomaly->anomalous_neighbors)
263     reported_peers++;
264   if (reported_peers == NUM_PEERS)
265   {
266     ok = 0;
267     GNUNET_SCHEDULER_cancel (shutdown_task);
268     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
269   }
270   return GNUNET_YES;
271 }
272
273
274 /**
275  * Task that pushes fake anomalies to running peers
276  */
277 static void
278 force_anomaly_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
279 {
280   struct TestPeer *peer = cls;
281
282   peer->delay_task = GNUNET_SCHEDULER_NO_TASK;
283   GNUNET_SENSOR_force_anomaly (peer->sensor, (char *) sensor_name, GNUNET_YES,
284                                NULL, NULL);
285 }
286
287
288 /**
289  * Callback to be called when sensor service connect operation is completed
290  *
291  * @param cls the callback closure from functions generating an operation
292  * @param op the operation that has been finished
293  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
294  * @param emsg error message in case the operation has failed; will be NULL if
295  *          operation has executed successfully.
296  */
297 static void
298 sensor_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
299                    void *ca_result, const char *emsg)
300 {
301   struct TestPeer *peer = cls;
302   struct GNUNET_SENSOR_Handle *sensor = ca_result;
303
304   peer->sensor = sensor;
305   peer->delay_task =
306       GNUNET_SCHEDULER_add_delayed (ANOMALY_DELAY, &force_anomaly_task, peer);
307 }
308
309
310 /**
311  * Adapter function called to establish a connection to sensor service.
312  *
313  * @param cls closure
314  * @param cfg configuration of the peer to connect to; will be available until
315  *          GNUNET_TESTBED_operation_done() is called on the operation returned
316  *          from GNUNET_TESTBED_service_connect()
317  * @return service handle to return in 'op_result', NULL on error
318  */
319 static void *
320 sensor_connect_adapter (void *cls,
321                         const struct GNUNET_CONFIGURATION_Handle *cfg)
322 {
323   struct GNUNET_SENSOR_Handle *sensor;
324
325   sensor = GNUNET_SENSOR_connect (cfg);
326   return sensor;
327 }
328
329
330 /**
331  * Adapter function called to destroy a connection to sensor service.
332  *
333  * @param cls closure
334  * @param op_result service handle returned from the connect adapter
335  */
336 static void
337 sensor_disconnect_adapter (void *cls, void *op_result)
338 {
339   struct GNUNET_SENSOR_Handle *sensor = op_result;
340
341   GNUNET_SENSOR_disconnect (sensor);
342 }
343
344
345 /**
346  * Callback to be called when sensor service is started
347  *
348  * @param cls the callback closure from functions generating an operation
349  * @param op the operation that has been finished
350  * @param emsg error message in case the operation has failed; will be NULL if
351  *          operation has executed successfully.
352  */
353 static void
354 sensor_service_started (void *cls, struct GNUNET_TESTBED_Operation *op,
355                         const char *emsg)
356 {
357   struct TestPeer *peer = cls;
358
359   if (NULL != emsg)
360   {
361     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ERROR: %s.\n", emsg);
362     GNUNET_assert (0);
363   }
364   peer->sensor_op =
365       GNUNET_TESTBED_service_connect (NULL, peer->testbed_peer, "sensor",
366                                       &sensor_connect_cb, peer,
367                                       &sensor_connect_adapter,
368                                       &sensor_disconnect_adapter, NULL);
369   GNUNET_TESTBED_operation_done (op);
370 }
371
372
373 /**
374  * Callback to be called when peerstore service connect operation is completed
375  *
376  * @param cls the callback closure from functions generating an operation
377  * @param op the operation that has been finished
378  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
379  * @param emsg error message in case the operation has failed; will be NULL if
380  *          operation has executed successfully.
381  */
382 static void
383 peerstore_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
384                       void *ca_result, const char *emsg)
385 {
386   struct TestPeer *peer;
387
388   peer = peer_head;
389   while (NULL != peer)
390   {
391     GNUNET_PEERSTORE_watch (peerstore, "sensordashboard-anomalies",
392                             &peer->peer_id, sensor_name, &peerstore_watch_cb,
393                             peer);
394     /* Start sensor service */
395     GNUNET_TESTBED_peer_manage_service (NULL, peer->testbed_peer, "sensor",
396                                         &sensor_service_started, peer, 1);
397     peer = peer->next;
398   }
399 }
400
401
402 /**
403  * Adapter function called to establish a connection to peerstore service.
404  *
405  * @param cls closure
406  * @param cfg configuration of the peer to connect to; will be available until
407  *          GNUNET_TESTBED_operation_done() is called on the operation returned
408  *          from GNUNET_TESTBED_service_connect()
409  * @return service handle to return in 'op_result', NULL on error
410  */
411 static void *
412 peerstore_connect_adapter (void *cls,
413                            const struct GNUNET_CONFIGURATION_Handle *cfg)
414 {
415   peerstore = GNUNET_PEERSTORE_connect (cfg);
416   GNUNET_assert (NULL != peerstore);
417   return peerstore;
418 }
419
420
421 /**
422  * Adapter function called to destroy a connection to peerstore service.
423  *
424  * @param cls closure
425  * @param op_result service handle returned from the connect adapter
426  */
427 static void
428 peerstore_disconnect_adapter (void *cls, void *op_result)
429 {
430   GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
431   peerstore = NULL;
432   peerstore_op = NULL;
433 }
434
435
436 /**
437  * Callback to be called when dashboard service is started
438  *
439  * @param cls the callback closure from functions generating an operation
440  * @param op the operation that has been finished
441  * @param emsg error message in case the operation has failed; will be NULL if
442  *          operation has executed successfully.
443  */
444 static void
445 dashboard_started (void *cls, struct GNUNET_TESTBED_Operation *op,
446                    const char *emsg)
447 {
448   if (NULL != emsg)
449   {
450     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ERROR: %s.\n", emsg);
451     GNUNET_assert (0);
452   }
453   GNUNET_TESTBED_operation_done (op);
454   /* Connect to peerstore service on first peer */
455   peerstore_op =
456       GNUNET_TESTBED_service_connect (NULL, peer_head->testbed_peer,
457                                       "peerstore", &peerstore_connect_cb, NULL,
458                                       &peerstore_connect_adapter,
459                                       &peerstore_disconnect_adapter, NULL);
460 }
461
462
463 /**
464  * Callback to be called when the requested peer information is available
465  *
466  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
467  * @param op the operation this callback corresponds to
468  * @param pinfo the result; will be NULL if the operation has failed
469  * @param emsg error message if the operation has failed; will be NULL if the
470  *          operation is successfull
471  */
472 static void
473 peer_info_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
474               const struct GNUNET_TESTBED_PeerInformation *pinfo,
475               const char *emsg)
476 {
477   struct GNUNET_TESTBED_Peer *testbed_peer = cb_cls;
478   struct TestPeer *peer;
479
480   peer = GNUNET_new (struct TestPeer);
481
482   peer->testbed_peer = testbed_peer;
483   peer->delay_task = GNUNET_SCHEDULER_NO_TASK;
484   GNUNET_CRYPTO_get_peer_identity (pinfo->result.cfg, &peer->peer_id);
485   if (NULL == peer_head)        /* First peer (collection point) */
486   {
487     /* Rewrite sensor with collection point peer id */
488     write_new_sensor_dir (peer);
489   }
490   GNUNET_CONTAINER_DLL_insert_tail (peer_head, peer_tail, peer);
491   started_peers++;
492   if (NUM_PEERS == started_peers)
493   {
494     /* Start dashboard service on first peer */
495     GNUNET_TESTBED_peer_manage_service (NULL, peer_head->testbed_peer,
496                                         "sensordashboard", &dashboard_started,
497                                         NULL, 1);
498   }
499   GNUNET_TESTBED_operation_done (op);
500 }
501
502
503 /**
504  * Signature of a main function for a testcase.
505  *
506  * @param cls closure
507  * @param h the run handle
508  * @param num_peers number of peers in 'peers'
509  * @param peers handle to peers run in the testbed.  NULL upon timeout (see
510  *          GNUNET_TESTBED_test_run()).
511  * @param links_succeeded the number of overlay link connection attempts that
512  *          succeeded
513  * @param links_failed the number of overlay link connection attempts that
514  *          failed
515  * @see GNUNET_TESTBED_test_run()
516  */
517 static void
518 test_master (void *cls, struct GNUNET_TESTBED_RunHandle *h,
519              unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers,
520              unsigned int links_succeeded, unsigned int links_failed)
521 {
522   int i;
523
524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525               "%d peers started. %d links succeeded. %d links failed.\n",
526               num_peers, links_succeeded, links_failed);
527   GNUNET_assert (NUM_PEERS == num_peers);
528   GNUNET_assert (0 == links_failed);
529   /* Schedule test timeout */
530   shutdown_task =
531       GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &do_shutdown, NULL);
532   /* Collect peer information */
533   for (i = 0; i < num_peers; i++)
534   {
535     GNUNET_TESTBED_peer_get_information (peers[i],
536                                          GNUNET_TESTBED_PIT_CONFIGURATION,
537                                          &peer_info_cb, peers[i]);
538   }
539 }
540
541
542 int
543 main (int argc, char *argv[])
544 {
545   GNUNET_log_setup (testname, "INFO", NULL);
546   if (GNUNET_OK ==
547       GNUNET_TESTBED_test_run (testname, cfg_filename, NUM_PEERS, 0, NULL, NULL,
548                                &test_master, NULL))
549     return ok;
550   return 1;
551 }