LCOV - code coverage report
Current view: top level - test - test_mainloop.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 222 222 100.0 %
Date: 2021-11-24 03:28:48 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.14