Merge branch 'maint-0.4.8' into release-0.4.8
[tor.git] / src / test / test_periodic_event.c
blob58565f6af10a351b69a22ab46dce55495a1220c7
1 /* Copyright (c) 2018-2021, 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_metrics.h"
21 #include "feature/hs/hs_service.h"
22 #include "core/mainloop/mainloop.h"
23 #include "core/mainloop/netstatus.h"
24 #include "core/mainloop/periodic.h"
26 /** Helper function: This is replaced in some tests for the event callbacks so
27 * we don't actually go into the code path of those callbacks. */
28 static int
29 dumb_event_fn(time_t now, const or_options_t *options)
31 (void) now;
32 (void) options;
34 /* Will get rescheduled in 300 seconds. It just can't be 0. */
35 return 300;
38 static void
39 register_dummy_hidden_service(hs_service_t *service)
41 memset(service, 0, sizeof(hs_service_t));
42 memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
43 (void) register_service(get_hs_service_map(), service);
46 static void
47 test_pe_initialize(void *arg)
49 (void) arg;
51 /* Initialize the events but the callback won't get called since we would
52 * need to run the main loop and then wait for a second delaying the unit
53 * tests. Instead, we'll test the callback work independently elsewhere. */
54 initialize_periodic_events();
55 periodic_events_connect_all();
56 set_network_participation(false);
57 rescan_periodic_events(get_options());
59 /* Validate that all events have been set up. */
60 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
61 periodic_event_item_t *item = &mainloop_periodic_events[i];
62 tt_assert(item->ev);
63 tt_assert(item->fn);
64 tt_u64_op(item->last_action_time, OP_EQ, 0);
65 /* Every event must have role(s) assign to it. This is done statically. */
66 tt_u64_op(item->roles, OP_NE, 0);
67 int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
68 !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
69 tt_uint_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
72 done:
73 teardown_periodic_events();
76 static void
77 test_pe_launch(void *arg)
79 hs_service_t service, *to_remove = NULL;
80 or_options_t *options;
82 (void) arg;
84 hs_init();
85 /* We need to put tor in hibernation live state so the events requiring
86 * network gets enabled. */
87 consider_hibernation(time(NULL));
89 set_network_participation(true);
91 /* Hack: We'll set a dumb fn() of each events so they don't get called when
92 * dispatching them. We just want to test the state of the callbacks, not
93 * the whole code path. */
94 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
95 periodic_event_item_t *item = &mainloop_periodic_events[i];
96 item->fn = dumb_event_fn;
99 options = get_options_mutable();
100 options->SocksPort_set = 1;
101 periodic_events_on_new_options(options);
103 #if 0
104 /* Lets make sure that before initialization, we can't scan the periodic
105 * events list and launch them. Lets try by being a Client. */
106 /* XXXX We make sure these events are initialized now way earlier than we
107 * did before. */
108 for (int i = 0; periodic_events[i].name; ++i) {
109 periodic_event_item_t *item = &periodic_events[i];
110 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
112 #endif /* 0 */
114 initialize_periodic_events();
115 periodic_events_connect_all();
117 /* Now that we've initialized, rescan the list to launch. */
118 periodic_events_on_new_options(options);
120 int mask = PERIODIC_EVENT_ROLE_CLIENT|PERIODIC_EVENT_ROLE_ALL|
121 PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
122 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
123 periodic_event_item_t *item = &mainloop_periodic_events[i];
124 int should_be_enabled = !!(item->roles & mask);
125 tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
126 // enabled or not, the event has not yet been run.
127 tt_u64_op(item->last_action_time, OP_EQ, 0);
130 /* Remove Client but become a Relay. */
131 options->SocksPort_set = 0;
132 options->ORPort_set = 1;
133 periodic_events_on_new_options(options);
135 unsigned roles = get_my_roles(options);
136 tt_uint_op(roles, OP_EQ,
137 PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER|
138 PERIODIC_EVENT_ROLE_ALL|PERIODIC_EVENT_ROLE_NET_PARTICIPANT);
140 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
141 periodic_event_item_t *item = &mainloop_periodic_events[i];
142 /* Only Client role should be disabled. */
143 if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
144 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
146 if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
147 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
149 /* Non Relay role should be disabled, except for Dirserver. */
150 if (!(item->roles & roles)) {
151 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
155 /* Disable everything and we'll enable them ALL. */
156 options->SocksPort_set = 0;
157 options->ORPort_set = 0;
158 options->DisableNetwork = 1;
159 set_network_participation(false);
160 periodic_events_on_new_options(options);
162 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
163 periodic_event_item_t *item = &mainloop_periodic_events[i];
164 int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
165 !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
166 tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
169 /* Enable everything. */
170 options->SocksPort_set = 1; options->ORPort_set = 1;
171 options->BridgeRelay = 1; options->AuthoritativeDir = 1;
172 options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
173 options->DisableNetwork = 0;
174 set_network_participation(true);
175 register_dummy_hidden_service(&service);
176 periodic_events_on_new_options(options);
177 /* Note down the reference because we need to remove this service from the
178 * global list before the hs_free_all() call so it doesn't try to free
179 * memory on the stack. Furthermore, we can't remove it now else it will
180 * trigger a rescan of the event disabling the HS service event. */
181 to_remove = &service;
183 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
184 periodic_event_item_t *item = &mainloop_periodic_events[i];
185 tt_int_op(periodic_event_is_enabled(item), OP_EQ,
186 (item->roles != PERIODIC_EVENT_ROLE_CONTROLEV));
189 done:
190 if (to_remove) {
191 hs_metrics_service_free(&service);
192 remove_service(get_hs_service_map(), to_remove);
194 hs_free_all();
197 static void
198 test_pe_get_roles(void *arg)
200 int roles;
202 (void) arg;
204 /* Just so the HS global map exists. */
205 hs_init();
207 or_options_t *options = get_options_mutable();
208 tt_assert(options);
209 set_network_participation(true);
211 const int ALL = PERIODIC_EVENT_ROLE_ALL |
212 PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
214 /* Nothing configured, should be no roles. */
215 tt_assert(net_is_disabled());
216 roles = get_my_roles(options);
217 tt_int_op(roles, OP_EQ, ALL);
219 /* Indicate we have a SocksPort, roles should be come Client. */
220 options->SocksPort_set = 1;
221 roles = get_my_roles(options);
222 tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT|ALL);
224 /* Now, we'll add a ORPort so should now be a Relay + Client. */
225 options->ORPort_set = 1;
226 roles = get_my_roles(options);
227 tt_int_op(roles, OP_EQ,
228 (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
229 PERIODIC_EVENT_ROLE_DIRSERVER | ALL));
231 /* Now add a Bridge. */
232 options->BridgeRelay = 1;
233 roles = get_my_roles(options);
234 tt_int_op(roles, OP_EQ,
235 (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
236 PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER |
237 ALL));
238 tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
239 /* Unset client so we can solely test Router role. */
240 options->SocksPort_set = 0;
241 roles = get_my_roles(options);
242 tt_int_op(roles, OP_EQ,
243 PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER |
244 ALL);
246 /* Reset options so we can test authorities. */
247 options->SocksPort_set = 0;
248 options->ORPort_set = 0;
249 options->BridgeRelay = 0;
250 roles = get_my_roles(options);
251 tt_int_op(roles, OP_EQ, ALL);
253 /* Now upgrade to Dirauth. */
254 options->DirPort_set = 1;
255 options->AuthoritativeDir = 1;
256 options->V3AuthoritativeDir = 1;
257 roles = get_my_roles(options);
258 tt_int_op(roles, OP_EQ,
259 PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
260 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
262 /* Now Bridge Authority. */
263 options->V3AuthoritativeDir = 0;
264 options->BridgeAuthoritativeDir = 1;
265 roles = get_my_roles(options);
266 tt_int_op(roles, OP_EQ,
267 PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
268 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
270 /* Move that bridge auth to become a relay. */
271 options->ORPort_set = 1;
272 roles = get_my_roles(options);
273 tt_int_op(roles, OP_EQ,
274 (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY
275 | PERIODIC_EVENT_ROLE_DIRSERVER|ALL));
276 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
278 /* And now an Hidden service. */
279 hs_service_t service;
280 register_dummy_hidden_service(&service);
281 roles = get_my_roles(options);
282 /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
283 remove_service(get_hs_service_map(), &service);
284 hs_metrics_service_free(&service);
285 tt_int_op(roles, OP_EQ,
286 (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
287 PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER |
288 ALL));
289 tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
291 done:
292 hs_free_all();
295 static void
296 test_pe_hs_service(void *arg)
298 hs_service_t service, *to_remove = NULL;
300 (void) arg;
302 hs_init();
303 /* We need to put tor in hibernation live state so the events requiring
304 * network gets enabled. */
305 consider_hibernation(time(NULL));
306 /* Initialize the events so we can enable them */
307 initialize_periodic_events();
308 periodic_events_connect_all();
310 /* Hack: We'll set a dumb fn() of each events so they don't get called when
311 * dispatching them. We just want to test the state of the callbacks, not
312 * the whole code path. */
313 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
314 periodic_event_item_t *item = &mainloop_periodic_events[i];
315 item->fn = dumb_event_fn;
318 /* This should trigger a rescan of the list and enable the HS service
319 * events. */
320 register_dummy_hidden_service(&service);
321 /* Note down the reference because we need to remove this service from the
322 * global list before the hs_free_all() call so it doesn't try to free
323 * memory on the stack. Furthermore, we can't remove it now else it will
324 * trigger a rescan of the event disabling the HS service event. */
325 to_remove = &service;
327 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
328 periodic_event_item_t *item = &mainloop_periodic_events[i];
329 if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
330 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
333 to_remove = NULL;
335 /* Remove the service from the global map, it should trigger a rescan and
336 * disable the HS service events. */
337 remove_service(get_hs_service_map(), &service);
338 hs_metrics_service_free(&service);
339 for (int i = 0; mainloop_periodic_events[i].name; ++i) {
340 periodic_event_item_t *item = &mainloop_periodic_events[i];
341 if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
342 tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
346 done:
347 if (to_remove) {
348 hs_metrics_service_free(&service);
349 remove_service(get_hs_service_map(), to_remove);
351 hs_free_all();
354 #define PE_TEST(name) \
355 { #name, test_pe_## name , TT_FORK, NULL, NULL }
357 struct testcase_t periodic_event_tests[] = {
358 PE_TEST(initialize),
359 PE_TEST(launch),
360 PE_TEST(get_roles),
361 PE_TEST(hs_service),
363 END_OF_TESTCASES