[tor-commits] [tor/master] test: Add periodic events unit tests

nickm at torproject.org nickm at torproject.org
Mon Apr 23 15:04:20 UTC 2018


commit 665e23c59a370157c5e3526e29590798b1933ed5
Author: David Goulet <dgoulet at torproject.org>
Date:   Wed Apr 18 14:50:07 2018 -0400

    test: Add periodic events unit tests
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/or/main.c                  |   4 +-
 src/or/main.h                  |   5 +
 src/test/include.am            |   1 +
 src/test/test.c                |   1 +
 src/test/test.h                |   1 +
 src/test/test_periodic_event.c | 256 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 266 insertions(+), 2 deletions(-)

diff --git a/src/or/main.c b/src/or/main.c
index 0a796c0fa..595246bfc 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1351,7 +1351,7 @@ CALLBACK(write_stats_file);
 /* Now we declare an array of periodic_event_item_t for each periodic event */
 #define CALLBACK(name, r) PERIODIC_EVENT(name, r)
 
-static periodic_event_item_t periodic_events[] = {
+STATIC periodic_event_item_t periodic_events[] = {
   /* Everyone needs to run those. */
   CALLBACK(add_entropy, PERIODIC_EVENT_ROLE_ALL),
   CALLBACK(check_expired_networkstatus, PERIODIC_EVENT_ROLE_ALL),
@@ -1440,7 +1440,7 @@ find_periodic_event(const char *name)
 
 /** Return a bitmask of the roles this tor instance is configured for using
  * the given options. */
-static int
+STATIC int
 get_my_roles(const or_options_t *options)
 {
   tor_assert(options);
diff --git a/src/or/main.h b/src/or/main.h
index 5220b1321..57ac8573a 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -98,8 +98,13 @@ STATIC void init_connection_lists(void);
 STATIC void close_closeable_connections(void);
 STATIC void initialize_periodic_events(void);
 STATIC void teardown_periodic_events(void);
+STATIC int get_my_roles(const or_options_t *options);
 #ifdef TOR_UNIT_TESTS
 extern smartlist_t *connection_array;
+
+/* We need the periodic_event_item_t definition. */
+#include "periodic.h"
+extern periodic_event_item_t periodic_events[];
 #endif
 #endif /* defined(MAIN_PRIVATE) */
 
diff --git a/src/test/include.am b/src/test/include.am
index 474da3f88..b59517a13 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -144,6 +144,7 @@ src_test_test_SOURCES = \
 	src/test/test_oom.c \
 	src/test/test_oos.c \
 	src/test/test_options.c \
+	src/test/test_periodic_event.c \
 	src/test/test_policy.c \
 	src/test/test_procmon.c \
 	src/test/test_proto_http.c \
diff --git a/src/test/test.c b/src/test/test.c
index 422e181b9..2963f169c 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -863,6 +863,7 @@ struct testgroup_t testgroups[] = {
   { "oom/", oom_tests },
   { "oos/", oos_tests },
   { "options/", options_tests },
+  { "periodic-event/" , periodic_event_tests },
   { "policy/" , policy_tests },
   { "procmon/", procmon_tests },
   { "proto/http/", proto_http_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 1728831ed..15965ccaf 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -239,6 +239,7 @@ extern struct testcase_t nodelist_tests[];
 extern struct testcase_t oom_tests[];
 extern struct testcase_t oos_tests[];
 extern struct testcase_t options_tests[];
+extern struct testcase_t periodic_event_tests[];
 extern struct testcase_t policy_tests[];
 extern struct testcase_t procmon_tests[];
 extern struct testcase_t proto_http_tests[];
diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c
new file mode 100644
index 000000000..1a9f4351e
--- /dev/null
+++ b/src/test/test_periodic_event.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_periodic_event.c
+ * \brief Test the periodic events that Tor uses for different roles. They are
+ *        part of the libevent mainloop
+ */
+
+#define CONFIG_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define MAIN_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+
+#include "or.h"
+#include "config.h"
+#include "hs_service.h"
+#include "main.h"
+#include "periodic.h"
+
+/** Helper function: This is replaced in some tests for the event callbacks so
+ * we don't actually go into the code path of those callbacks. */
+static int
+dumb_event_fn(time_t now, const or_options_t *options)
+{
+  (void) now;
+  (void) options;
+
+  /* Will get rescheduled in 300 seconds. It just can't be 0. */
+  return 300;
+}
+
+static void
+register_dummy_hidden_service(hs_service_t *service)
+{
+  memset(service, 0, sizeof(hs_service_t));
+  memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
+  (void) register_service(get_hs_service_map(), service);
+}
+
+static void
+test_pe_initialize(void *arg)
+{
+  (void) arg;
+
+  /* Initialize the events but the callback won't get called since we would
+   * need to run the main loop and then wait for a second delaying the unit
+   * tests. Instead, we'll test the callback work indepedently elsewhere. */
+  initialize_periodic_events();
+
+  /* Validate that all events have been set up. */
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    tt_assert(item->ev);
+    tt_assert(item->fn);
+    tt_u64_op(item->last_action_time, OP_EQ, 0);
+    /* Every event must have role(s) assign to it. This is done statically. */
+    tt_u64_op(item->roles, OP_NE, 0);
+    tt_uint_op(periodic_event_is_enabled(item), OP_EQ, 0);
+  }
+
+ done:
+  teardown_periodic_events();
+}
+
+static void
+test_pe_launch(void *arg)
+{
+  hs_service_t service;
+  or_options_t *options;
+
+  (void) arg;
+
+  hs_init();
+
+  /* Hack: We'll set a dumb fn() of each events so they don't get called when
+   * dispatching them. We just want to test the state of the callbacks, not
+   * the whole code path. */
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    item->fn = dumb_event_fn;
+  }
+
+  /* Lets make sure that before intialization, we can't scan the periodic
+   * events list and launch them. Lets try by being a Client. */
+  options = get_options_mutable();
+  options->SocksPort_set = 1;
+  periodic_events_on_new_options(options);
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+  }
+
+  initialize_periodic_events();
+
+  /* Now that we've initialized, rescan the list to launch. */
+  periodic_events_on_new_options(options);
+
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    if (item->roles & PERIODIC_EVENT_ROLE_CLIENT) {
+      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
+      tt_u64_op(item->last_action_time, OP_NE, 0);
+    } else {
+      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+      tt_u64_op(item->last_action_time, OP_EQ, 0);
+    }
+  }
+
+  /* Remove Client but become a Relay. */
+  options->SocksPort_set = 0;
+  options->ORPort_set = 1;
+  periodic_events_on_new_options(options);
+
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    /* Only Client role should be disabled. */
+    if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
+      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+      /* Was previously enabled so they should never be to 0. */
+      tt_u64_op(item->last_action_time, OP_NE, 0);
+    }
+    if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
+      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
+      tt_u64_op(item->last_action_time, OP_NE, 0);
+    }
+    /* Non Relay role should be disabled! */
+    if (!(item->roles & PERIODIC_EVENT_ROLE_RELAY)) {
+      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+    }
+  }
+
+  /* Disable everything and we'll enable them ALL. */
+  options->SocksPort_set = 0;
+  options->ORPort_set = 0;
+  periodic_events_on_new_options(options);
+
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
+  }
+
+  /* Enable everything. */
+  options->SocksPort_set = 1; options->ORPort_set = 1;
+  options->BridgeRelay = 1; options->AuthoritativeDir = 1;
+  options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
+  register_dummy_hidden_service(&service);
+  periodic_events_on_new_options(options);
+  /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
+  remove_service(get_hs_service_map(), &service);
+
+  for (int i = 0; periodic_events[i].name; ++i) {
+    periodic_event_item_t *item = &periodic_events[i];
+    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
+  }
+
+ done:
+  hs_free_all();
+}
+
+static void
+test_pe_get_roles(void *arg)
+{
+  int roles;
+
+  (void) arg;
+
+  /* Just so the HS global map exists. */
+  hs_init();
+
+  or_options_t *options = get_options_mutable();
+  tt_assert(options);
+
+  /* Nothing configured, should be no roles. */
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, 0);
+
+  /* Indicate we have a SocksPort, roles should be come Client. */
+  options->SocksPort_set = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT);
+
+  /* Now, we'll add a ORPort so should now be a Relay + Client. */
+  options->ORPort_set = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ,
+            (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY));
+
+  /* Now add a Bridge. */
+  options->BridgeRelay = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ,
+            (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
+             PERIODIC_EVENT_ROLE_BRIDGE));
+  tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
+  /* Unset client so we can solely test Router role. */
+  options->SocksPort_set = 0;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_ROUTER);
+
+  /* Reset options so we can test authorities. */
+  options->SocksPort_set = 0;
+  options->ORPort_set = 0;
+  options->BridgeRelay = 0;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, 0);
+
+  /* Now upgrade to Dirauth. */
+  options->AuthoritativeDir = 1;
+  options->V3AuthoritativeDir = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_DIRAUTH);
+  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
+
+  /* Now Bridge Authority. */
+  options->V3AuthoritativeDir = 0;
+  options->BridgeAuthoritativeDir = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_BRIDGEAUTH);
+  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
+
+  /* Move that bridge auth to become a relay. */
+  options->ORPort_set = 1;
+  roles = get_my_roles(options);
+  tt_int_op(roles, OP_EQ,
+            (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY));
+  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
+
+  /* And now an Hidden service. */
+  hs_service_t service;
+  register_dummy_hidden_service(&service);
+  roles = get_my_roles(options);
+  /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
+  remove_service(get_hs_service_map(), &service);
+  tt_int_op(roles, OP_EQ,
+            (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
+             PERIODIC_EVENT_ROLE_HS_SERVICE));
+  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
+
+ done:
+  hs_free_all();
+}
+
+#define PE_TEST(name) \
+  { #name, test_pe_## name , TT_FORK, NULL, NULL }
+
+struct testcase_t periodic_event_tests[] = {
+  PE_TEST(initialize),
+  PE_TEST(launch),
+  PE_TEST(get_roles),
+
+  END_OF_TESTCASES
+};
+





More information about the tor-commits mailing list