Merge branch 'maint-0.4.0'
[tor.git] / src / test / test_mainloop.c
blobed6b8a9b6601997054d497541c86534c8d078f21
1 /* Copyright (c) 2018-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file test_mainloop.c
6 * \brief Tests for functions closely related to the Tor main loop
7 */
9 #define CONFIG_PRIVATE
10 #define MAINLOOP_PRIVATE
11 #define STATEFILE_PRIVATE
13 #include "test/test.h"
14 #include "test/log_test_helpers.h"
16 #include "core/or/or.h"
17 #include "core/mainloop/connection.h"
18 #include "core/mainloop/mainloop.h"
19 #include "core/mainloop/netstatus.h"
21 #include "feature/hs/hs_service.h"
23 #include "app/config/config.h"
24 #include "app/config/statefile.h"
25 #include "app/config/or_state_st.h"
27 static const uint64_t BILLION = 1000000000;
29 static void
30 test_mainloop_update_time_normal(void *arg)
32 (void)arg;
34 monotime_enable_test_mocking();
35 /* This is arbitrary */
36 uint64_t mt_now = UINT64_C(7493289274986);
37 /* This time is in the past as of when this test was written. */
38 time_t now = 1525272090;
39 monotime_coarse_set_mock_time_nsec(mt_now);
40 reset_uptime();
41 update_current_time(now);
42 tt_int_op(approx_time(), OP_EQ, now);
43 tt_int_op(get_uptime(), OP_EQ, 0);
45 update_current_time(now); // Same time as before is a no-op.
46 tt_int_op(get_uptime(), OP_EQ, 0);
48 now += 1;
49 mt_now += BILLION;
50 monotime_coarse_set_mock_time_nsec(mt_now);
51 update_current_time(now);
52 tt_int_op(approx_time(), OP_EQ, now);
53 tt_int_op(get_uptime(), OP_EQ, 1);
55 now += 2; // two-second jump is unremarkable.
56 mt_now += 2*BILLION;
57 update_current_time(now);
58 monotime_coarse_set_mock_time_nsec(mt_now);
59 tt_int_op(approx_time(), OP_EQ, now);
60 tt_int_op(get_uptime(), OP_EQ, 3);
62 now -= 1; // a one-second hop backwards is also unremarkable.
63 update_current_time(now);
64 tt_int_op(approx_time(), OP_EQ, now); // it changes the approx time...
65 tt_int_op(get_uptime(), OP_EQ, 3); // but it doesn't roll back our uptime
67 done:
68 monotime_disable_test_mocking();
71 static void
72 test_mainloop_update_time_jumps(void *arg)
74 (void)arg;
76 monotime_enable_test_mocking();
77 /* This is arbitrary */
78 uint64_t mt_now = UINT64_C(7493289274986);
79 /* This time is in the past as of when this test was written. */
80 time_t now = 220897152;
81 monotime_coarse_set_mock_time_nsec(mt_now);
82 reset_uptime();
83 update_current_time(now);
84 tt_int_op(approx_time(), OP_EQ, now);
85 tt_int_op(get_uptime(), OP_EQ, 0);
87 /* Put some uptime on the clock.. */
88 now += 3;
89 mt_now += 3*BILLION;
90 monotime_coarse_set_mock_time_nsec(mt_now);
91 update_current_time(now);
92 tt_int_op(approx_time(), OP_EQ, now);
93 tt_int_op(get_uptime(), OP_EQ, 3);
95 /* Now try jumping forward and backward, without updating the monotonic
96 * clock. */
97 setup_capture_of_logs(LOG_NOTICE);
98 now += 1800;
99 update_current_time(now);
100 expect_single_log_msg_containing(
101 "Your system clock just jumped 1800 seconds forward");
102 tt_int_op(approx_time(), OP_EQ, now);
103 tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
104 mock_clean_saved_logs();
106 now -= 600;
107 update_current_time(now);
108 expect_single_log_msg_containing(
109 "Your system clock just jumped 600 seconds backward");
110 tt_int_op(approx_time(), OP_EQ, now);
111 tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
112 mock_clean_saved_logs();
114 /* uptime tracking should go normally now if the clock moves sensibly. */
115 now += 2;
116 mt_now += 2*BILLION;
117 update_current_time(now);
118 tt_int_op(approx_time(), OP_EQ, now);
119 tt_int_op(get_uptime(), OP_EQ, 5);
121 /* If we skip forward by a few minutes but the monotonic clock agrees,
122 * we've just been idle: that counts as not worth warning about. */
123 now += 1800;
124 mt_now += 1800*BILLION;
125 monotime_coarse_set_mock_time_nsec(mt_now);
126 update_current_time(now);
127 expect_no_log_entry();
128 tt_int_op(approx_time(), OP_EQ, now);
129 tt_int_op(get_uptime(), OP_EQ, 5); // this doesn't count to uptime, though.
131 /* If we skip forward by a long time, even if the clock agrees, it's
132 * idnless that counts. */
133 now += 4000;
134 mt_now += 4000*BILLION;
135 monotime_coarse_set_mock_time_nsec(mt_now);
136 update_current_time(now);
137 expect_single_log_msg_containing("Tor has been idle for 4000 seconds");
138 tt_int_op(approx_time(), OP_EQ, now);
139 tt_int_op(get_uptime(), OP_EQ, 5);
141 done:
142 teardown_capture_of_logs();
143 monotime_disable_test_mocking();
146 static int schedule_rescan_called = 0;
147 static void
148 mock_schedule_rescan_periodic_events(void)
150 ++schedule_rescan_called;
153 static void
154 test_mainloop_user_activity(void *arg)
156 (void)arg;
157 const time_t start = 1542658829;
158 update_approx_time(start);
160 MOCK(schedule_rescan_periodic_events, mock_schedule_rescan_periodic_events);
162 reset_user_activity(start);
163 tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
165 set_network_participation(false);
167 // reset can move backwards and forwards, but does not change network
168 // participation.
169 reset_user_activity(start-10);
170 tt_i64_op(get_last_user_activity_time(), OP_EQ, start-10);
171 reset_user_activity(start+10);
172 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
174 tt_int_op(schedule_rescan_called, OP_EQ, 0);
175 tt_int_op(false, OP_EQ, is_participating_on_network());
177 // "note" can only move forward. Calling it from a non-participating
178 // state makes us rescan the periodic callbacks and set participation.
179 note_user_activity(start+20);
180 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+20);
181 tt_int_op(true, OP_EQ, is_participating_on_network());
182 tt_int_op(schedule_rescan_called, OP_EQ, 1);
184 // Calling it again will move us forward, but not call rescan again.
185 note_user_activity(start+25);
186 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
187 tt_int_op(true, OP_EQ, is_participating_on_network());
188 tt_int_op(schedule_rescan_called, OP_EQ, 1);
190 // We won't move backwards.
191 note_user_activity(start+20);
192 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
193 tt_int_op(true, OP_EQ, is_participating_on_network());
194 tt_int_op(schedule_rescan_called, OP_EQ, 1);
196 // We _will_ adjust if the clock jumps though.
197 netstatus_note_clock_jumped(500);
198 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+525);
200 netstatus_note_clock_jumped(-400);
201 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+125);
203 done:
204 UNMOCK(schedule_rescan_periodic_events);
207 static unsigned int
208 mock_get_num_services(void)
210 return 1;
213 static connection_t *
214 mock_connection_gbtu(int type)
216 (void) type;
217 return (void *)"hello fellow connections";
220 static void
221 test_mainloop_check_participation(void *arg)
223 (void)arg;
224 or_options_t *options = options_new();
225 const time_t start = 1542658829;
226 const time_t ONE_DAY = 24*60*60;
228 // Suppose we've been idle for a day or two
229 reset_user_activity(start - 2*ONE_DAY);
230 set_network_participation(true);
231 check_network_participation_callback(start, options);
232 tt_int_op(is_participating_on_network(), OP_EQ, false);
233 tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
235 // suppose we've been idle for 2 days... but we are a server.
236 reset_user_activity(start - 2*ONE_DAY);
237 options->ORPort_set = 1;
238 set_network_participation(true);
239 check_network_participation_callback(start+2, options);
240 tt_int_op(is_participating_on_network(), OP_EQ, true);
241 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+2);
242 options->ORPort_set = 0;
244 // idle for 2 days, but we have a hidden service.
245 reset_user_activity(start - 2*ONE_DAY);
246 set_network_participation(true);
247 MOCK(hs_service_get_num_services, mock_get_num_services);
248 check_network_participation_callback(start+3, options);
249 tt_int_op(is_participating_on_network(), OP_EQ, true);
250 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+3);
251 UNMOCK(hs_service_get_num_services);
253 // idle for 2 days but we have at least one user connection
254 MOCK(connection_get_by_type_nonlinked, mock_connection_gbtu);
255 reset_user_activity(start - 2*ONE_DAY);
256 set_network_participation(true);
257 options->DormantTimeoutDisabledByIdleStreams = 1;
258 check_network_participation_callback(start+10, options);
259 tt_int_op(is_participating_on_network(), OP_EQ, true);
260 tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
262 // as above, but DormantTimeoutDisabledByIdleStreams is not set
263 reset_user_activity(start - 2*ONE_DAY);
264 set_network_participation(true);
265 options->DormantTimeoutDisabledByIdleStreams = 0;
266 check_network_participation_callback(start+13, options);
267 tt_int_op(is_participating_on_network(), OP_EQ, false);
268 tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
269 UNMOCK(connection_get_by_type_nonlinked);
270 options->DormantTimeoutDisabledByIdleStreams = 1;
272 // idle for 2 days but DormantClientTimeout is 3 days
273 reset_user_activity(start - 2*ONE_DAY);
274 set_network_participation(true);
275 options->DormantClientTimeout = ONE_DAY * 3;
276 check_network_participation_callback(start+30, options);
277 tt_int_op(is_participating_on_network(), OP_EQ, true);
278 tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
280 done:
281 or_options_free(options);
282 UNMOCK(hs_service_get_num_services);
283 UNMOCK(connection_get_by_type_nonlinked);
286 static void
287 test_mainloop_dormant_load_state(void *arg)
289 (void)arg;
290 or_state_t *state = or_state_new();
291 const time_t start = 1543956575;
293 reset_user_activity(0);
294 set_network_participation(false);
296 // When we construct a new state, it starts out in "auto" mode.
297 tt_int_op(state->Dormant, OP_EQ, -1);
299 // Initializing from "auto" makes us start out (by default) non-Dormant,
300 // with activity right now.
301 netstatus_load_from_state(state, start);
302 tt_assert(is_participating_on_network());
303 tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
305 // Initializing from dormant clears the last user activity time, and
306 // makes us dormant.
307 state->Dormant = 1;
308 netstatus_load_from_state(state, start);
309 tt_assert(! is_participating_on_network());
310 tt_i64_op(get_last_user_activity_time(), OP_EQ, 0);
312 // Initializing from non-dormant sets the last user activity time, and
313 // makes us non-dormant.
314 state->Dormant = 0;
315 state->MinutesSinceUserActivity = 123;
316 netstatus_load_from_state(state, start);
317 tt_assert(is_participating_on_network());
318 tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60);
320 // If we would start dormant, but DormantCanceledByStartup is set, then
321 // we start up non-dormant.
322 state->Dormant = 1;
323 get_options_mutable()->DormantCanceledByStartup = 1;
324 netstatus_load_from_state(state, start);
325 tt_assert(is_participating_on_network());
326 tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
328 done:
329 or_state_free(state);
332 static void
333 test_mainloop_dormant_save_state(void *arg)
335 (void)arg;
336 or_state_t *state = or_state_new();
337 const time_t start = 1543956575;
339 // Can we save a non-dormant state correctly?
340 reset_user_activity(start - 1000);
341 set_network_participation(true);
342 netstatus_flush_to_state(state, start);
344 tt_int_op(state->Dormant, OP_EQ, 0);
345 tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 1000 / 60);
347 // Can we save a dormant state correctly?
348 set_network_participation(false);
349 netstatus_flush_to_state(state, start);
351 tt_int_op(state->Dormant, OP_EQ, 1);
352 tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
354 done:
355 or_state_free(state);
358 #define MAINLOOP_TEST(name) \
359 { #name, test_mainloop_## name , TT_FORK, NULL, NULL }
361 struct testcase_t mainloop_tests[] = {
362 MAINLOOP_TEST(update_time_normal),
363 MAINLOOP_TEST(update_time_jumps),
364 MAINLOOP_TEST(user_activity),
365 MAINLOOP_TEST(check_participation),
366 MAINLOOP_TEST(dormant_load_state),
367 MAINLOOP_TEST(dormant_save_state),
368 END_OF_TESTCASES