1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 * \file test_mainloop.c
6 * \brief Tests for functions closely related to the Tor main loop
10 #define MAINLOOP_PRIVATE
11 #define STATEFILE_PRIVATE
13 #include "test/test.h"
14 #include "test/log_test_helpers.h"
16 #include "lib/confmgt/confmgt.h"
18 #include "core/or/or.h"
19 #include "core/mainloop/connection.h"
20 #include "core/mainloop/mainloop.h"
21 #include "core/mainloop/mainloop_state_st.h"
22 #include "core/mainloop/mainloop_sys.h"
23 #include "core/mainloop/netstatus.h"
25 #include "feature/hs/hs_service.h"
27 #include "app/config/config.h"
28 #include "app/config/statefile.h"
29 #include "app/config/or_state_st.h"
31 #include "app/main/subsysmgr.h"
33 static const uint64_t BILLION
= 1000000000;
36 test_mainloop_update_time_normal(void *arg
)
40 monotime_enable_test_mocking();
41 /* This is arbitrary */
42 uint64_t mt_now
= UINT64_C(7493289274986);
43 /* This time is in the past as of when this test was written. */
44 time_t now
= 1525272090;
45 monotime_coarse_set_mock_time_nsec(mt_now
);
47 update_current_time(now
);
48 tt_int_op(approx_time(), OP_EQ
, now
);
49 tt_int_op(get_uptime(), OP_EQ
, 0);
51 update_current_time(now
); // Same time as before is a no-op.
52 tt_int_op(get_uptime(), OP_EQ
, 0);
56 monotime_coarse_set_mock_time_nsec(mt_now
);
57 update_current_time(now
);
58 tt_int_op(approx_time(), OP_EQ
, now
);
59 tt_int_op(get_uptime(), OP_EQ
, 1);
61 now
+= 2; // two-second jump is unremarkable.
63 update_current_time(now
);
64 monotime_coarse_set_mock_time_nsec(mt_now
);
65 tt_int_op(approx_time(), OP_EQ
, now
);
66 tt_int_op(get_uptime(), OP_EQ
, 3);
68 now
-= 1; // a one-second hop backwards is also unremarkable.
69 update_current_time(now
);
70 tt_int_op(approx_time(), OP_EQ
, now
); // it changes the approx time...
71 tt_int_op(get_uptime(), OP_EQ
, 3); // but it doesn't roll back our uptime
74 monotime_disable_test_mocking();
78 test_mainloop_update_time_jumps(void *arg
)
82 monotime_enable_test_mocking();
83 /* This is arbitrary */
84 uint64_t mt_now
= UINT64_C(7493289274986);
85 /* This time is in the past as of when this test was written. */
86 time_t now
= 220897152;
87 monotime_coarse_set_mock_time_nsec(mt_now
);
89 update_current_time(now
);
90 tt_int_op(approx_time(), OP_EQ
, now
);
91 tt_int_op(get_uptime(), OP_EQ
, 0);
93 /* Put some uptime on the clock.. */
96 monotime_coarse_set_mock_time_nsec(mt_now
);
97 update_current_time(now
);
98 tt_int_op(approx_time(), OP_EQ
, now
);
99 tt_int_op(get_uptime(), OP_EQ
, 3);
101 /* Now try jumping forward and backward, without updating the monotonic
103 setup_capture_of_logs(LOG_NOTICE
);
105 update_current_time(now
);
106 expect_single_log_msg_containing(
107 "Your system clock just jumped 1800 seconds forward");
108 tt_int_op(approx_time(), OP_EQ
, now
);
109 tt_int_op(get_uptime(), OP_EQ
, 3); // no uptime change.
110 mock_clean_saved_logs();
113 update_current_time(now
);
114 expect_single_log_msg_containing(
115 "Your system clock just jumped 600 seconds backward");
116 tt_int_op(approx_time(), OP_EQ
, now
);
117 tt_int_op(get_uptime(), OP_EQ
, 3); // no uptime change.
118 mock_clean_saved_logs();
120 /* uptime tracking should go normally now if the clock moves sensibly. */
123 update_current_time(now
);
124 tt_int_op(approx_time(), OP_EQ
, now
);
125 tt_int_op(get_uptime(), OP_EQ
, 5);
127 /* If we skip forward by a few minutes but the monotonic clock agrees,
128 * we've just been idle: that counts as not worth warning about. */
130 mt_now
+= 1800*BILLION
;
131 monotime_coarse_set_mock_time_nsec(mt_now
);
132 update_current_time(now
);
133 expect_no_log_entry();
134 tt_int_op(approx_time(), OP_EQ
, now
);
135 tt_int_op(get_uptime(), OP_EQ
, 5); // this doesn't count to uptime, though.
137 /* If we skip forward by a long time, even if the clock agrees, it's
138 * idnless that counts. */
140 mt_now
+= 4000*BILLION
;
141 monotime_coarse_set_mock_time_nsec(mt_now
);
142 update_current_time(now
);
143 expect_single_log_msg_containing("Tor has been idle for 4000 seconds");
144 tt_int_op(approx_time(), OP_EQ
, now
);
145 tt_int_op(get_uptime(), OP_EQ
, 5);
148 teardown_capture_of_logs();
149 monotime_disable_test_mocking();
152 static int schedule_rescan_called
= 0;
154 mock_schedule_rescan_periodic_events(void)
156 ++schedule_rescan_called
;
160 test_mainloop_user_activity(void *arg
)
163 const time_t start
= 1542658829;
164 update_approx_time(start
);
166 MOCK(schedule_rescan_periodic_events
, mock_schedule_rescan_periodic_events
);
168 reset_user_activity(start
);
169 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
);
171 set_network_participation(false);
173 // reset can move backwards and forwards, but does not change network
175 reset_user_activity(start
-10);
176 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
-10);
177 reset_user_activity(start
+10);
178 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+10);
180 tt_int_op(schedule_rescan_called
, OP_EQ
, 0);
181 tt_int_op(false, OP_EQ
, is_participating_on_network());
183 // "note" can only move forward. Calling it from a non-participating
184 // state makes us rescan the periodic callbacks and set participation.
185 note_user_activity(start
+20);
186 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+20);
187 tt_int_op(true, OP_EQ
, is_participating_on_network());
188 tt_int_op(schedule_rescan_called
, OP_EQ
, 1);
190 // Calling it again will move us forward, but not call rescan again.
191 note_user_activity(start
+25);
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 won't move backwards.
197 note_user_activity(start
+20);
198 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+25);
199 tt_int_op(true, OP_EQ
, is_participating_on_network());
200 tt_int_op(schedule_rescan_called
, OP_EQ
, 1);
202 // We _will_ adjust if the clock jumps though.
203 netstatus_note_clock_jumped(500);
204 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+525);
206 netstatus_note_clock_jumped(-400);
207 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+125);
210 UNMOCK(schedule_rescan_periodic_events
);
214 mock_get_num_services(void)
219 static connection_t
*
220 mock_connection_gbtu(int type
)
223 return (void *)"hello fellow connections";
227 test_mainloop_check_participation(void *arg
)
230 or_options_t
*options
= options_new();
231 const time_t start
= 1542658829;
232 const time_t ONE_DAY
= 24*60*60;
234 // Suppose we've been idle for a day or two
235 reset_user_activity(start
- 2*ONE_DAY
);
236 set_network_participation(true);
237 check_network_participation_callback(start
, options
);
238 tt_int_op(is_participating_on_network(), OP_EQ
, false);
239 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
-2*ONE_DAY
);
241 // suppose we've been idle for 2 days... but we are a server.
242 reset_user_activity(start
- 2*ONE_DAY
);
243 options
->ORPort_set
= 1;
244 set_network_participation(true);
245 check_network_participation_callback(start
+2, options
);
246 tt_int_op(is_participating_on_network(), OP_EQ
, true);
247 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+2);
248 options
->ORPort_set
= 0;
250 // idle for 2 days, but we have a hidden service.
251 reset_user_activity(start
- 2*ONE_DAY
);
252 set_network_participation(true);
253 MOCK(hs_service_get_num_services
, mock_get_num_services
);
254 check_network_participation_callback(start
+3, options
);
255 tt_int_op(is_participating_on_network(), OP_EQ
, true);
256 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+3);
257 UNMOCK(hs_service_get_num_services
);
259 // idle for 2 days but we have at least one user connection
260 MOCK(connection_get_by_type_nonlinked
, mock_connection_gbtu
);
261 reset_user_activity(start
- 2*ONE_DAY
);
262 set_network_participation(true);
263 options
->DormantTimeoutDisabledByIdleStreams
= 1;
264 check_network_participation_callback(start
+10, options
);
265 tt_int_op(is_participating_on_network(), OP_EQ
, true);
266 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
+10);
268 // as above, but DormantTimeoutDisabledByIdleStreams is not set
269 reset_user_activity(start
- 2*ONE_DAY
);
270 set_network_participation(true);
271 options
->DormantTimeoutDisabledByIdleStreams
= 0;
272 check_network_participation_callback(start
+13, options
);
273 tt_int_op(is_participating_on_network(), OP_EQ
, false);
274 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
-2*ONE_DAY
);
275 UNMOCK(connection_get_by_type_nonlinked
);
276 options
->DormantTimeoutDisabledByIdleStreams
= 1;
278 // idle for 2 days but DormantClientTimeout is 3 days
279 reset_user_activity(start
- 2*ONE_DAY
);
280 set_network_participation(true);
281 options
->DormantClientTimeout
= ONE_DAY
* 3;
282 check_network_participation_callback(start
+30, options
);
283 tt_int_op(is_participating_on_network(), OP_EQ
, true);
284 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
-2*ONE_DAY
);
287 or_options_free(options
);
288 UNMOCK(hs_service_get_num_services
);
289 UNMOCK(connection_get_by_type_nonlinked
);
293 test_mainloop_dormant_load_state(void *arg
)
296 or_state_t
*or_state
= or_state_new();
297 mainloop_state_t
*state
;
299 int idx
= subsystems_get_state_idx(&sys_mainloop
);
300 tor_assert(idx
>= 0);
301 state
= config_mgr_get_obj_mutable(get_state_mgr(), or_state
, idx
);
303 const time_t start
= 1543956575;
305 reset_user_activity(0);
306 set_network_participation(false);
308 // When we construct a new state, it starts out in "auto" mode.
309 tt_int_op(state
->Dormant
, OP_EQ
, -1);
311 // Initializing from "auto" makes us start out (by default) non-Dormant,
312 // with activity right now.
313 netstatus_load_from_state(state
, start
);
314 tt_assert(is_participating_on_network());
315 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
);
317 // Initializing from dormant clears the last user activity time, and
320 netstatus_load_from_state(state
, start
);
321 tt_assert(! is_participating_on_network());
322 tt_i64_op(get_last_user_activity_time(), OP_EQ
, 0);
324 // Initializing from non-dormant sets the last user activity time, and
325 // makes us non-dormant.
327 state
->MinutesSinceUserActivity
= 123;
328 netstatus_load_from_state(state
, start
);
329 tt_assert(is_participating_on_network());
330 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
- 123*60);
332 // If we would start dormant, but DormantCanceledByStartup is set, then
333 // we start up non-dormant.
335 get_options_mutable()->DormantCanceledByStartup
= 1;
336 netstatus_load_from_state(state
, start
);
337 tt_assert(is_participating_on_network());
338 tt_i64_op(get_last_user_activity_time(), OP_EQ
, start
);
341 or_state_free(or_state
);
345 test_mainloop_dormant_save_state(void *arg
)
348 mainloop_state_t
*state
= tor_malloc_zero(sizeof(mainloop_state_t
));
349 const time_t start
= 1543956575;
351 // Can we save a non-dormant state correctly?
352 reset_user_activity(start
- 1000);
353 set_network_participation(true);
354 netstatus_flush_to_state(state
, start
);
356 tt_int_op(state
->Dormant
, OP_EQ
, 0);
357 tt_int_op(state
->MinutesSinceUserActivity
, OP_EQ
, 1000 / 60);
359 // Can we save a dormant state correctly?
360 set_network_participation(false);
361 netstatus_flush_to_state(state
, start
);
363 tt_int_op(state
->Dormant
, OP_EQ
, 1);
364 tt_int_op(state
->MinutesSinceUserActivity
, OP_EQ
, 0);
370 #define MAINLOOP_TEST(name) \
371 { #name, test_mainloop_## name , TT_FORK, NULL, NULL }
373 struct testcase_t mainloop_tests
[] = {
374 MAINLOOP_TEST(update_time_normal
),
375 MAINLOOP_TEST(update_time_jumps
),
376 MAINLOOP_TEST(user_activity
),
377 MAINLOOP_TEST(check_participation
),
378 MAINLOOP_TEST(dormant_load_state
),
379 MAINLOOP_TEST(dormant_save_state
),