RECLAIM/OIDC: code cleanup
[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     if (NULL != op[i])
93       GNUNET_TESTBED_operation_done (op[i]);
94   }
95
96   if (NULL != timeout_tid)
97     GNUNET_SCHEDULER_cancel (timeout_tid);
98 }
99
100 static void
101 timeout_task (void *cls)
102 {
103   timeout_tid = NULL;
104   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
105               "Testcase timeout\n");
106
107   result = GNUNET_SYSERR;
108   GNUNET_SCHEDULER_shutdown();
109 }
110
111 /*
112  * The function is called every time the topology of connected
113  * peers to a peer changes.
114  */
115 int
116 statistics_iterator (void *cls,
117                      const char *subsystem,
118                      const char *name,
119                      uint64_t value,
120                      int is_persistent)
121 {
122   struct peerctx *p_ctx = (struct peerctx*) cls;
123
124   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
125               "Peer %d: %s = %llu\n",
126               p_ctx->index,
127               name,
128               (unsigned long long) value);
129
130   if (p_ctx->connections < value)
131     p_ctx->connections = value;
132
133   if (THRESHOLD <= value && GNUNET_NO == p_ctx->reported) {
134     p_ctx->reported = GNUNET_YES;
135     checked_peers++;
136     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
137                "Peer %d successfully connected to at least %d peers once.\n",
138                p_ctx->index,
139                THRESHOLD);
140
141     if (checked_peers == NUM_PEERS) {
142       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
143                "Test OK: All peers have connected to %d peers once.\n",
144                THRESHOLD);
145       result = GNUNET_YES;
146       GNUNET_SCHEDULER_shutdown();
147     }
148   }
149
150   return GNUNET_YES;
151 }
152
153 static void *
154 ca_statistics (void *cls,
155                const struct GNUNET_CONFIGURATION_Handle *cfg)
156 {
157   return GNUNET_STATISTICS_create ("topology", cfg);
158 }
159
160
161 void
162 da_statistics (void *cls,
163                void *op_result)
164 {
165   struct peerctx *p_ctx = (struct peerctx *) cls;
166
167   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
168                 (p_ctx->statistics, "topology", "# peers connected",
169                  statistics_iterator, p_ctx));
170
171   GNUNET_STATISTICS_destroy (p_ctx->statistics, GNUNET_NO);
172   p_ctx->statistics = NULL;
173
174   GNUNET_free (p_ctx);
175 }
176
177
178 static void
179 service_connect_complete (void *cls,
180                           struct GNUNET_TESTBED_Operation *op,
181                           void *ca_result,
182                           const char *emsg)
183 {
184   int ret;
185   struct peerctx *p_ctx = (struct peerctx*) cls;
186
187   if (NULL == ca_result)
188     GNUNET_SCHEDULER_shutdown();
189
190   p_ctx->statistics = ca_result;
191
192   ret = GNUNET_STATISTICS_watch (ca_result,
193                                  "topology",
194                                  "# peers connected",
195                                  statistics_iterator,
196                                  p_ctx);
197
198   if (GNUNET_NO == ret)
199     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
200                 "call to GNUNET_STATISTICS_watch() failed\n");
201 }
202
203 static void
204 notify_connect_complete (void *cls,
205                          struct GNUNET_TESTBED_Operation *op,
206                          const char *emsg)
207 {
208   GNUNET_TESTBED_operation_done (op);
209   if (NULL != emsg)
210   {
211     FPRINTF (stderr, "Failed to connect two peers: %s\n", emsg);
212     result = GNUNET_SYSERR;
213     GNUNET_SCHEDULER_shutdown ();
214     return;
215   }
216   connect_left--;
217 }
218
219 static void
220 do_connect (void *cls,
221             struct GNUNET_TESTBED_RunHandle *h,
222             unsigned int num_peers,
223             struct GNUNET_TESTBED_Peer **peers,
224             unsigned int links_succeeded,
225             unsigned int links_failed)
226 {
227   unsigned int i;
228   struct peerctx *p_ctx;
229
230   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
231               "Threshold is set to %d.\n",
232               THRESHOLD);
233
234   GNUNET_assert (NUM_PEERS == num_peers);
235
236   for (i=0;i<NUM_PEERS;i++)
237     {
238       p_ctx = GNUNET_new (struct peerctx);
239       p_ctx->index = i;
240       p_ctx->connections = 0;
241       p_ctx->reported = GNUNET_NO;
242
243       if (i<NUM_PEERS-1) {
244         connect_left++;
245         GNUNET_TESTBED_overlay_connect (NULL,
246                                         &notify_connect_complete, NULL,
247                                         peers[i], peers[i+1]);
248       }
249
250       op[i] =
251         GNUNET_TESTBED_service_connect (cls,
252                                         peers[i],
253                                         "statistics",
254                                         service_connect_complete,
255                                         p_ctx, /* cls of completion cb */
256                                         ca_statistics, /* connect adapter */
257                                         da_statistics, /* disconnect adapter */
258                                         p_ctx);
259
260     }
261
262   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
263   timeout_tid =
264     GNUNET_SCHEDULER_add_delayed (TIMEOUT,
265                                   &timeout_task,
266                                   NULL);
267 }
268
269
270 int
271 main (int argc, char *argv[])
272 {
273   result = GNUNET_SYSERR;
274   checked_peers = 0;
275
276   (void) GNUNET_TESTBED_test_run ("test-gnunet-daemon-topology",
277                                   "test_gnunet_daemon_topology_data.conf",
278                                   NUM_PEERS,
279                                   0, NULL, NULL,
280                                   &do_connect, NULL);
281   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology");
282
283   return (GNUNET_OK != result) ? 1 : 0;
284 }
285
286 /* end of test_gnunet_daemon_topology.c */