tighten formatting rules
[oweals/gnunet.git] / src / topology / test_gnunet_daemon_topology.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 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      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file topology/test_gnunet_daemon_topology.c
22  * @brief testcase for topology maintenance code
23  * @author Christian Grothoff
24  * @author xrs
25  */
26 #include "platform.h"
27 #include "gnunet_testbed_service.h"
28 #include "gnunet_statistics_service.h"
29
30
31 #define NUM_PEERS 8
32
33 /*
34  * The threshold defines the number of connection that are needed
35  * for one peer to pass the test. Be aware that setting NUM_PEERS
36  * too high can cause bandwidth problems for the testing peers.
37  * Normal should be 5KB/s per peer. See gnunet-config -s ats.
38  */
39 #define THRESHOLD NUM_PEERS / 2
40
41 /**
42  * How long until we give up on connecting the peers?
43  */
44 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
45
46 /*
47  * Store manual connections.
48  */
49 static unsigned int connect_left;
50
51 /*
52  * Result of the testcase.
53  */
54 static int result;
55
56 /*
57  * Peers that reached the threshold of connections.
58  */
59 static int checked_peers;
60
61 /*
62  * Testbed operations.
63  */
64 struct GNUNET_TESTBED_Operation *op[NUM_PEERS];
65
66 /*
67  * Timeout for testcase.
68  */
69 static struct GNUNET_SCHEDULER_Task *timeout_tid;
70
71 /*
72  * Peer context for every testbed peer.
73  */
74 struct peerctx
75 {
76   int index;
77   struct GNUNET_STATISTICS_Handle *statistics;
78   int connections;
79   int reported; /* GNUNET_NO | GNUNET_YES */
80 };
81
82
83 static void
84 shutdown_task (void *cls)
85 {
86   unsigned int i;
87
88   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
89               "Shutting down testcase\n");
90
91   for (i = 0; i < NUM_PEERS; i++)
92   {
93     if (NULL != op[i])
94       GNUNET_TESTBED_operation_done (op[i]);
95   }
96
97   if (NULL != timeout_tid)
98     GNUNET_SCHEDULER_cancel (timeout_tid);
99 }
100
101
102 static void
103 timeout_task (void *cls)
104 {
105   timeout_tid = NULL;
106   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
107               "Testcase timeout\n");
108
109   result = GNUNET_SYSERR;
110   GNUNET_SCHEDULER_shutdown ();
111 }
112
113
114 /*
115  * The function is called every time the topology of connected
116  * peers to a peer changes.
117  */
118 int
119 statistics_iterator (void *cls,
120                      const char *subsystem,
121                      const char *name,
122                      uint64_t value,
123                      int is_persistent)
124 {
125   struct peerctx *p_ctx = (struct peerctx*) cls;
126
127   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
128               "Peer %d: %s = %llu\n",
129               p_ctx->index,
130               name,
131               (unsigned long long) value);
132
133   if (p_ctx->connections < value)
134     p_ctx->connections = value;
135
136   if ((THRESHOLD <= value) && (GNUNET_NO == p_ctx->reported))
137   {
138     p_ctx->reported = GNUNET_YES;
139     checked_peers++;
140     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
141                 "Peer %d successfully connected to at least %d peers once.\n",
142                 p_ctx->index,
143                 THRESHOLD);
144
145     if (checked_peers == NUM_PEERS)
146     {
147       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
148                   "Test OK: All peers have connected to %d peers once.\n",
149                   THRESHOLD);
150       result = GNUNET_YES;
151       GNUNET_SCHEDULER_shutdown ();
152     }
153   }
154
155   return GNUNET_YES;
156 }
157
158
159 static void *
160 ca_statistics (void *cls,
161                const struct GNUNET_CONFIGURATION_Handle *cfg)
162 {
163   return GNUNET_STATISTICS_create ("topology", cfg);
164 }
165
166
167 void
168 da_statistics (void *cls,
169                void *op_result)
170 {
171   struct peerctx *p_ctx = (struct peerctx *) cls;
172
173   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
174                   (p_ctx->statistics, "topology", "# peers connected",
175                   statistics_iterator, p_ctx));
176
177   GNUNET_STATISTICS_destroy (p_ctx->statistics, GNUNET_NO);
178   p_ctx->statistics = NULL;
179
180   GNUNET_free (p_ctx);
181 }
182
183
184 static void
185 service_connect_complete (void *cls,
186                           struct GNUNET_TESTBED_Operation *op,
187                           void *ca_result,
188                           const char *emsg)
189 {
190   int ret;
191   struct peerctx *p_ctx = (struct peerctx*) cls;
192
193   if (NULL == ca_result)
194     GNUNET_SCHEDULER_shutdown ();
195
196   p_ctx->statistics = ca_result;
197
198   ret = GNUNET_STATISTICS_watch (ca_result,
199                                  "topology",
200                                  "# peers connected",
201                                  statistics_iterator,
202                                  p_ctx);
203
204   if (GNUNET_NO == ret)
205     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
206                 "call to GNUNET_STATISTICS_watch() failed\n");
207 }
208
209
210 static void
211 notify_connect_complete (void *cls,
212                          struct GNUNET_TESTBED_Operation *op,
213                          const char *emsg)
214 {
215   GNUNET_TESTBED_operation_done (op);
216   if (NULL != emsg)
217   {
218     fprintf (stderr, "Failed to connect two peers: %s\n", emsg);
219     result = GNUNET_SYSERR;
220     GNUNET_SCHEDULER_shutdown ();
221     return;
222   }
223   connect_left--;
224 }
225
226
227 static void
228 do_connect (void *cls,
229             struct GNUNET_TESTBED_RunHandle *h,
230             unsigned int num_peers,
231             struct GNUNET_TESTBED_Peer **peers,
232             unsigned int links_succeeded,
233             unsigned int links_failed)
234 {
235   unsigned int i;
236   struct peerctx *p_ctx;
237
238   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
239               "Threshold is set to %d.\n",
240               THRESHOLD);
241
242   GNUNET_assert (NUM_PEERS == num_peers);
243
244   for (i = 0; i < NUM_PEERS; i++)
245   {
246     p_ctx = GNUNET_new (struct peerctx);
247     p_ctx->index = i;
248     p_ctx->connections = 0;
249     p_ctx->reported = GNUNET_NO;
250
251     if (i < NUM_PEERS - 1)
252     {
253       connect_left++;
254       GNUNET_TESTBED_overlay_connect (NULL,
255                                       &notify_connect_complete, NULL,
256                                       peers[i], peers[i + 1]);
257     }
258
259     op[i] =
260       GNUNET_TESTBED_service_connect (cls,
261                                       peers[i],
262                                       "statistics",
263                                       service_connect_complete,
264                                       p_ctx,   /* cls of completion cb */
265                                       ca_statistics,   /* connect adapter */
266                                       da_statistics,   /* disconnect adapter */
267                                       p_ctx);
268   }
269
270   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
271   timeout_tid =
272     GNUNET_SCHEDULER_add_delayed (TIMEOUT,
273                                   &timeout_task,
274                                   NULL);
275 }
276
277
278 int
279 main (int argc, char *argv[])
280 {
281   result = GNUNET_SYSERR;
282   checked_peers = 0;
283
284   (void) GNUNET_TESTBED_test_run ("test-gnunet-daemon-topology",
285                                   "test_gnunet_daemon_topology_data.conf",
286                                   NUM_PEERS,
287                                   0, NULL, NULL,
288                                   &do_connect, NULL);
289   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology");
290
291   return (GNUNET_OK != result) ? 1 : 0;
292 }
293
294
295 /* end of test_gnunet_daemon_topology.c */