Fuzzing module for various string operations, currently focusing on
[tor.git] / src / test / test_periodic_event.c
blobf3d518eb7b6aae695cadcd98c9d1be5e5c180352
1 /* Copyright (c) 2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file test_periodic_event.c
6 * \brief Test the periodic events that Tor uses for different roles. They are
7 * part of the libevent mainloop
8 */
10 #define CONFIG_PRIVATE
11 #define HS_SERVICE_PRIVATE
12 #define MAINLOOP_PRIVATE
14 #include "test/test.h"
15 #include "test/test_helpers.h"
17 #include "core/or/or.h"
18 #include "app/config/config.h"
19 #include "feature/hibernate/hibernate.h"
20 #include "feature/hs/hs_service.h"
21 #include "core/mainloop/mainloop.h"
22 #include "core/mainloop/netstatus.h"
23 #include "core/mainloop/periodic.h"
25 /** Helper function: This is replaced in some tests for the event callbacks so
26 * we don't actually go into the code path of those callbacks. */
27 static int
28 dumb_event_fn(time_t now, const or_options_t *options)
30 (void) now;
31 (void) options;
33 /* Will get rescheduled in 300 seconds. It just can't be 0. */
34 return 300;
37 static void
38 register_dummy_hidden_service(hs_service_t *service)
40 memset(service, 0, sizeof(hs_service_t));
41 memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
42 (void) register_service(get_hs_service_map(), service);
45 static void
46 test_pe_initialize(void *arg)
48 (void) arg;
50 /* Initialize the events but the callback won't get called since we would
51 * need to run the main loop and then wait for a second delaying the unit
52 * tests. Instead, we'll test the callback work indepedently elsewhere. */
53 initialize_periodic_events();
54 set_network_participation(false);
55 rescan_periodic_events(get_options());
57 /* Validate that all events have been set up. */
58 for (int i = 0; periodic_events[i].name; ++i) {
59 periodic_event_item_t *item = &periodic_events[i];
60 tt_assert(item->ev);
61 tt_assert(item->fn);
62 tt_u64_op(item->last_action_time, OP_EQ, 0);
63 /* Every event must have role(s) assign to it. This is done statically. */
64 tt_u64_op(item->roles, OP_NE, 0);
65 int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
66 !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
67 tt_uint_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
70 done:
71 teardown_periodic_events();
74 static void
75 test_pe_launch(void *arg)
77 hs_service_t service, *to_remove = NULL;
78 or_options_t *options;
80 (void) arg;
82 hs_init();
83 /* We need to put tor in hibernation live state so the events requiring
84 * network gets enabled. */
85 consider_hibernation(time(NULL));
87 set_network_participation(true);
89 /* Hack: We'll set a dumb fn() of each events so they don't get called when
90 * dispatching them. We just want to test the state of the callbacks, not
91 * the whole code path. */
92 for (int i = 0; periodic_events[i].name; ++i) {
93 periodic_event_item_t *item = &periodic_events[i];
94 item->fn = dumb_event_fn;
97 options = get_options_mutable();
98 options->SocksPort_set = 1;
99 periodic_events_on_new_options(options);
101 #if 0
102 /* Lets make sure that before intialization, we can't scan the periodic
103 * events list and launch them. Lets try by being a Client. */
104 /* XXXX We make sure these events are initialized now way earlier than we
105 * did before. */
106 for (int i = 0; periodic_events[i].name; ++i) {
107 periodic_event_item_t *item = &periodic_events[i];
108 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
110 #endif
112 initialize_periodic_events();
114 /* Now that we've initialized, rescan the list to launch. */
115 periodic_events_on_new_options(options);
117 int mask = PERIODIC_EVENT_ROLE_CLIENT|PERIODIC_EVENT_ROLE_ALL|
118 PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
119 for (int i = 0; periodic_events[i].name; ++i) {
120 periodic_event_item_t *item = &periodic_events[i];
121 int should_be_enabled = !!(item->roles & mask);
122 tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
123 // enabled or not, the event has not yet been run.
124 tt_u64_op(item->last_action_time, OP_EQ, 0);
127 /* Remove Client but become a Relay. */
128 options->SocksPort_set = 0;
129 options->ORPort_set = 1;
130 periodic_events_on_new_options(options);
132 unsigned roles = get_my_roles(options);
133 tt_uint_op(roles, OP_EQ,
134 PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER|
135 PERIODIC_EVENT_ROLE_ALL|PERIODIC_EVENT_ROLE_NET_PARTICIPANT);
137 for (int i = 0; periodic_events[i].name; ++i) {
138 periodic_event_item_t *item = &periodic_events[i];
139 /* Only Client role should be disabled. */
140 if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
141 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
143 if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
144 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
146 /* Non Relay role should be disabled, except for Dirserver. */
147 if (!(item->roles & roles)) {
148 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
152 /* Disable everything and we'll enable them ALL. */
153 options->SocksPort_set = 0;
154 options->ORPort_set = 0;
155 options->DisableNetwork = 1;
156 set_network_participation(false);
157 periodic_events_on_new_options(options);
159 for (int i = 0; periodic_events[i].name; ++i) {
160 periodic_event_item_t *item = &periodic_events[i];
161 int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
162 !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
163 tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
166 /* Enable everything. */
167 options->SocksPort_set = 1; options->ORPort_set = 1;
168 options->BridgeRelay = 1; options->AuthoritativeDir = 1;
169 options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
170 options->DisableNetwork = 0;
171 set_network_participation(true);
172 register_dummy_hidden_service(&service);
173 periodic_events_on_new_options(options);
174 /* Note down the reference because we need to remove this service from the
175 * global list before the hs_free_all() call so it doesn't try to free
176 * memory on the stack. Furthermore, we can't remove it now else it will
177 * trigger a rescan of the event disabling the HS service event. */
178 to_remove = &service;
180 for (int i = 0; periodic_events[i].name; ++i) {
181 periodic_event_item_t *item = &periodic_events[i];
182 tt_int_op(periodic_event_is_enabled(item), OP_EQ,
183 (item->roles != PERIODIC_EVENT_ROLE_CONTROLEV));
186 done:
187 if (to_remove) {
188 remove_service(get_hs_service_map(), to_remove);
190 hs_free_all();
193 static void
194 test_pe_get_roles(void *arg)
196 int roles;
198 (void) arg;
200 /* Just so the HS global map exists. */
201 hs_init();
203 or_options_t *options = get_options_mutable();
204 tt_assert(options);
205 set_network_participation(true);
207 const int ALL = PERIODIC_EVENT_ROLE_ALL |
208 PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
210 /* Nothing configured, should be no roles. */
211 tt_assert(net_is_disabled());
212 roles = get_my_roles(options);
213 tt_int_op(roles, OP_EQ, ALL);
215 /* Indicate we have a SocksPort, roles should be come Client. */
216 options->SocksPort_set = 1;
217 roles = get_my_roles(options);
218 tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT|ALL);
220 /* Now, we'll add a ORPort so should now be a Relay + Client. */
221 options->ORPort_set = 1;
222 roles = get_my_roles(options);
223 tt_int_op(roles, OP_EQ,
224 (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
225 PERIODIC_EVENT_ROLE_DIRSERVER | ALL));
227 /* Now add a Bridge. */
228 options->BridgeRelay = 1;
229 roles = get_my_roles(options);
230 tt_int_op(roles, OP_EQ,
231 (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
232 PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER |
233 ALL));
234 tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
235 /* Unset client so we can solely test Router role. */
236 options->SocksPort_set = 0;
237 roles = get_my_roles(options);
238 tt_int_op(roles, OP_EQ,
239 PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER |
240 ALL);
242 /* Reset options so we can test authorities. */
243 options->SocksPort_set = 0;
244 options->ORPort_set = 0;
245 options->BridgeRelay = 0;
246 roles = get_my_roles(options);
247 tt_int_op(roles, OP_EQ, ALL);
249 /* Now upgrade to Dirauth. */
250 options->DirPort_set = 1;
251 options->AuthoritativeDir = 1;
252 options->V3AuthoritativeDir = 1;
253 roles = get_my_roles(options);
254 tt_int_op(roles, OP_EQ,
255 PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
256 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
258 /* Now Bridge Authority. */
259 options->V3AuthoritativeDir = 0;
260 options->BridgeAuthoritativeDir = 1;
261 roles = get_my_roles(options);
262 tt_int_op(roles, OP_EQ,
263 PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
264 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
266 /* Move that bridge auth to become a relay. */
267 options->ORPort_set = 1;
268 roles = get_my_roles(options);
269 tt_int_op(roles, OP_EQ,
270 (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY
271 | PERIODIC_EVENT_ROLE_DIRSERVER|ALL));
272 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
274 /* And now an Hidden service. */
275 hs_service_t service;
276 register_dummy_hidden_service(&service);
277 roles = get_my_roles(options);
278 /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
279 remove_service(get_hs_service_map(), &service);
280 tt_int_op(roles, OP_EQ,
281 (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
282 PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER |
283 ALL));
284 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
286 done:
287 hs_free_all();
290 static void
291 test_pe_hs_service(void *arg)
293 hs_service_t service, *to_remove = NULL;
295 (void) arg;
297 hs_init();
298 /* We need to put tor in hibernation live state so the events requiring
299 * network gets enabled. */
300 consider_hibernation(time(NULL));
301 /* Initialize the events so we can enable them */
302 initialize_periodic_events();
304 /* Hack: We'll set a dumb fn() of each events so they don't get called when
305 * dispatching them. We just want to test the state of the callbacks, not
306 * the whole code path. */
307 for (int i = 0; periodic_events[i].name; ++i) {
308 periodic_event_item_t *item = &periodic_events[i];
309 item->fn = dumb_event_fn;
312 /* This should trigger a rescan of the list and enable the HS service
313 * events. */
314 register_dummy_hidden_service(&service);
315 /* Note down the reference because we need to remove this service from the
316 * global list before the hs_free_all() call so it doesn't try to free
317 * memory on the stack. Furthermore, we can't remove it now else it will
318 * trigger a rescan of the event disabling the HS service event. */
319 to_remove = &service;
321 for (int i = 0; periodic_events[i].name; ++i) {
322 periodic_event_item_t *item = &periodic_events[i];
323 if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
324 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
327 to_remove = NULL;
329 /* Remove the service from the global map, it should trigger a rescan and
330 * disable the HS service events. */
331 remove_service(get_hs_service_map(), &service);
332 for (int i = 0; periodic_events[i].name; ++i) {
333 periodic_event_item_t *item = &periodic_events[i];
334 if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
335 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
339 done:
340 if (to_remove) {
341 remove_service(get_hs_service_map(), to_remove);
343 hs_free_all();
346 #define PE_TEST(name) \
347 { #name, test_pe_## name , TT_FORK, NULL, NULL }
349 struct testcase_t periodic_event_tests[] = {
350 PE_TEST(initialize),
351 PE_TEST(launch),
352 PE_TEST(get_roles),
353 PE_TEST(hs_service),
355 END_OF_TESTCASES