LCOV - code coverage report
Current view: top level - test - test_periodic_event.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 161 170 94.7 %
Date: 2021-11-24 03:28:48 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /* Copyright (c) 2018-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       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             :  */
       9             : 
      10             : #define CONFIG_PRIVATE
      11             : #define HS_SERVICE_PRIVATE
      12             : #define MAINLOOP_PRIVATE
      13             : 
      14             : #include "test/test.h"
      15             : #include "test/test_helpers.h"
      16             : 
      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"
      25             : 
      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           0 : dumb_event_fn(time_t now, const or_options_t *options)
      30             : {
      31           0 :   (void) now;
      32           0 :   (void) options;
      33             : 
      34             :   /* Will get rescheduled in 300 seconds. It just can't be 0. */
      35           0 :   return 300;
      36             : }
      37             : 
      38             : static void
      39           3 : register_dummy_hidden_service(hs_service_t *service)
      40             : {
      41           3 :   memset(service, 0, sizeof(hs_service_t));
      42           3 :   memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
      43           3 :   (void) register_service(get_hs_service_map(), service);
      44           3 : }
      45             : 
      46             : static void
      47           1 : test_pe_initialize(void *arg)
      48             : {
      49           1 :   (void) arg;
      50             : 
      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 indepedently elsewhere. */
      54           1 :   initialize_periodic_events();
      55           1 :   periodic_events_connect_all();
      56           1 :   set_network_participation(false);
      57           1 :   rescan_periodic_events(get_options());
      58             : 
      59             :   /* Validate that all events have been set up. */
      60          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
      61          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
      62          19 :     tt_assert(item->ev);
      63          19 :     tt_assert(item->fn);
      64          19 :     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          19 :     tt_u64_op(item->roles, OP_NE, 0);
      67          19 :     int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
      68             :       !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
      69          19 :     tt_uint_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
      70             :   }
      71             : 
      72           1 :  done:
      73           1 :   teardown_periodic_events();
      74           1 : }
      75             : 
      76             : static void
      77           1 : test_pe_launch(void *arg)
      78             : {
      79           1 :   hs_service_t service, *to_remove = NULL;
      80           1 :   or_options_t *options;
      81             : 
      82           1 :   (void) arg;
      83             : 
      84           1 :   hs_init();
      85             :   /* We need to put tor in hibernation live state so the events requiring
      86             :    * network gets enabled. */
      87           1 :   consider_hibernation(time(NULL));
      88             : 
      89           1 :   set_network_participation(true);
      90             : 
      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          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
      95          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
      96          19 :     item->fn = dumb_event_fn;
      97             :   }
      98             : 
      99           1 :   options = get_options_mutable();
     100           1 :   options->SocksPort_set = 1;
     101           1 :   periodic_events_on_new_options(options);
     102             : 
     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);
     111             :   }
     112             : #endif /* 0 */
     113             : 
     114           1 :   initialize_periodic_events();
     115           1 :   periodic_events_connect_all();
     116             : 
     117             :   /* Now that we've initialized, rescan the list to launch. */
     118           1 :   periodic_events_on_new_options(options);
     119             : 
     120           1 :   int mask = PERIODIC_EVENT_ROLE_CLIENT|PERIODIC_EVENT_ROLE_ALL|
     121             :     PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
     122          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     123          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     124          19 :     int should_be_enabled = !!(item->roles & mask);
     125          19 :     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          19 :     tt_u64_op(item->last_action_time, OP_EQ, 0);
     128             :   }
     129             : 
     130             :   /* Remove Client but become a Relay. */
     131           1 :   options->SocksPort_set = 0;
     132           1 :   options->ORPort_set = 1;
     133           1 :   periodic_events_on_new_options(options);
     134             : 
     135           1 :   unsigned roles = get_my_roles(options);
     136           1 :   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);
     139             : 
     140          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     141          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     142             :     /* Only Client role should be disabled. */
     143          19 :     if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
     144           0 :       tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
     145             :     }
     146          19 :     if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
     147           0 :       tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
     148             :     }
     149             :     /* Non Relay role should be disabled, except for Dirserver. */
     150          19 :     if (!(item->roles & roles)) {
     151          19 :       tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
     152             :     }
     153             :   }
     154             : 
     155             :   /* Disable everything and we'll enable them ALL. */
     156           1 :   options->SocksPort_set = 0;
     157           1 :   options->ORPort_set = 0;
     158           1 :   options->DisableNetwork = 1;
     159           1 :   set_network_participation(false);
     160           1 :   periodic_events_on_new_options(options);
     161             : 
     162          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     163          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     164          19 :     int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) &&
     165             :       !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET);
     166          19 :     tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled);
     167             :   }
     168             : 
     169             :   /* Enable everything. */
     170           1 :   options->SocksPort_set = 1; options->ORPort_set = 1;
     171           1 :   options->BridgeRelay = 1; options->AuthoritativeDir = 1;
     172           1 :   options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
     173           1 :   options->DisableNetwork = 0;
     174           1 :   set_network_participation(true);
     175           1 :   register_dummy_hidden_service(&service);
     176           1 :   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           1 :   to_remove = &service;
     182             : 
     183          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     184          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     185          19 :     tt_int_op(periodic_event_is_enabled(item), OP_EQ,
     186             :               (item->roles != PERIODIC_EVENT_ROLE_CONTROLEV));
     187             :   }
     188             : 
     189           1 :  done:
     190           0 :   if (to_remove) {
     191           1 :     hs_metrics_service_free(&service);
     192           1 :     remove_service(get_hs_service_map(), to_remove);
     193             :   }
     194           1 :   hs_free_all();
     195           1 : }
     196             : 
     197             : static void
     198           1 : test_pe_get_roles(void *arg)
     199             : {
     200           1 :   int roles;
     201             : 
     202           1 :   (void) arg;
     203             : 
     204             :   /* Just so the HS global map exists. */
     205           1 :   hs_init();
     206             : 
     207           1 :   or_options_t *options = get_options_mutable();
     208           1 :   tt_assert(options);
     209           1 :   set_network_participation(true);
     210             : 
     211           1 :   const int ALL = PERIODIC_EVENT_ROLE_ALL |
     212             :     PERIODIC_EVENT_ROLE_NET_PARTICIPANT;
     213             : 
     214             :   /* Nothing configured, should be no roles. */
     215           1 :   tt_assert(net_is_disabled());
     216           1 :   roles = get_my_roles(options);
     217           1 :   tt_int_op(roles, OP_EQ, ALL);
     218             : 
     219             :   /* Indicate we have a SocksPort, roles should be come Client. */
     220           1 :   options->SocksPort_set = 1;
     221           1 :   roles = get_my_roles(options);
     222           1 :   tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT|ALL);
     223             : 
     224             :   /* Now, we'll add a ORPort so should now be a Relay + Client. */
     225           1 :   options->ORPort_set = 1;
     226           1 :   roles = get_my_roles(options);
     227           1 :   tt_int_op(roles, OP_EQ,
     228             :             (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
     229             :              PERIODIC_EVENT_ROLE_DIRSERVER | ALL));
     230             : 
     231             :   /* Now add a Bridge. */
     232           1 :   options->BridgeRelay = 1;
     233           1 :   roles = get_my_roles(options);
     234           1 :   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           1 :   tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
     239             :   /* Unset client so we can solely test Router role. */
     240           1 :   options->SocksPort_set = 0;
     241           1 :   roles = get_my_roles(options);
     242           1 :   tt_int_op(roles, OP_EQ,
     243             :             PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER |
     244             :             ALL);
     245             : 
     246             :   /* Reset options so we can test authorities. */
     247           1 :   options->SocksPort_set = 0;
     248           1 :   options->ORPort_set = 0;
     249           1 :   options->BridgeRelay = 0;
     250           1 :   roles = get_my_roles(options);
     251           1 :   tt_int_op(roles, OP_EQ, ALL);
     252             : 
     253             :   /* Now upgrade to Dirauth. */
     254           1 :   options->DirPort_set = 1;
     255           1 :   options->AuthoritativeDir = 1;
     256           1 :   options->V3AuthoritativeDir = 1;
     257           1 :   roles = get_my_roles(options);
     258           1 :   tt_int_op(roles, OP_EQ,
     259             :             PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
     260           1 :   tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
     261             : 
     262             :   /* Now Bridge Authority. */
     263           1 :   options->V3AuthoritativeDir = 0;
     264           1 :   options->BridgeAuthoritativeDir = 1;
     265           1 :   roles = get_my_roles(options);
     266           1 :   tt_int_op(roles, OP_EQ,
     267             :             PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER|ALL);
     268           1 :   tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
     269             : 
     270             :   /* Move that bridge auth to become a relay. */
     271           1 :   options->ORPort_set = 1;
     272           1 :   roles = get_my_roles(options);
     273           1 :   tt_int_op(roles, OP_EQ,
     274             :             (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY
     275             :              | PERIODIC_EVENT_ROLE_DIRSERVER|ALL));
     276           1 :   tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
     277             : 
     278             :   /* And now an Hidden service. */
     279           1 :   hs_service_t service;
     280           1 :   register_dummy_hidden_service(&service);
     281           1 :   roles = get_my_roles(options);
     282             :   /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
     283           1 :   remove_service(get_hs_service_map(), &service);
     284           1 :   hs_metrics_service_free(&service);
     285           1 :   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           1 :   tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
     290             : 
     291           1 :  done:
     292           1 :   hs_free_all();
     293           1 : }
     294             : 
     295             : static void
     296           1 : test_pe_hs_service(void *arg)
     297             : {
     298           1 :   hs_service_t service, *to_remove = NULL;
     299             : 
     300           1 :   (void) arg;
     301             : 
     302           1 :   hs_init();
     303             :   /* We need to put tor in hibernation live state so the events requiring
     304             :    * network gets enabled. */
     305           1 :   consider_hibernation(time(NULL));
     306             :   /* Initialize the events so we can enable them */
     307           1 :   initialize_periodic_events();
     308           1 :   periodic_events_connect_all();
     309             : 
     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          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     314          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     315          19 :     item->fn = dumb_event_fn;
     316             :   }
     317             : 
     318             :   /* This should trigger a rescan of the list and enable the HS service
     319             :    * events. */
     320           1 :   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           1 :   to_remove = &service;
     326             : 
     327          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     328          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     329          19 :     if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
     330          19 :       tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
     331             :     }
     332             :   }
     333           1 :   to_remove = NULL;
     334             : 
     335             :   /* Remove the service from the global map, it should trigger a rescan and
     336             :    * disable the HS service events. */
     337           1 :   remove_service(get_hs_service_map(), &service);
     338           1 :   hs_metrics_service_free(&service);
     339          20 :   for (int i = 0; mainloop_periodic_events[i].name; ++i) {
     340          19 :     periodic_event_item_t *item = &mainloop_periodic_events[i];
     341          19 :     if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
     342          19 :       tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
     343             :     }
     344             :   }
     345             : 
     346           1 :  done:
     347           1 :   if (to_remove) {
     348           0 :     hs_metrics_service_free(&service);
     349           0 :     remove_service(get_hs_service_map(), to_remove);
     350             :   }
     351           1 :   hs_free_all();
     352           1 : }
     353             : 
     354             : #define PE_TEST(name) \
     355             :   { #name, test_pe_## name , TT_FORK, NULL, NULL }
     356             : 
     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),
     362             : 
     363             :   END_OF_TESTCASES
     364             : };

Generated by: LCOV version 1.14