Commit 79d3e94f authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

prop271: Tests for the highlevel or_state_t encode/decode functions

parent 171981f8
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1115,8 +1115,8 @@ remove_guard_from_confirmed_and_primary_lists(guard_selection_t *gs,
/** Return true iff <b>guard</b> is currently "listed" -- that is, it
 * appears in the consensus, or as a configured bridge (as
 * appropriate) */
static int
entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
MOCK_IMPL(STATIC int,
entry_guard_is_listed,(guard_selection_t *gs, const entry_guard_t *guard))
{
  if (gs->type == GS_TYPE_BRIDGE) {
    return NULL != get_bridge_info_for_guard(guard);
+2 −0
Original line number Diff line number Diff line
@@ -498,6 +498,8 @@ STATIC guard_selection_t *guard_selection_new(const char *name,
STATIC guard_selection_t *get_guard_selection_by_name(
          const char *name, guard_selection_type_t type, int create_if_absent);
STATIC void guard_selection_free(guard_selection_t *gs);
MOCK_DECL(STATIC int, entry_guard_is_listed,
          (guard_selection_t *gs, const entry_guard_t *guard));
STATIC const char *choose_guard_selection(const or_options_t *options,
                                          const networkstatus_t *ns,
                                          const char *old_selection,
+238 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include "bridges.h"
#include "circuitlist.h"
#include "config.h"
#include "confparse.h"
#include "entrynodes.h"
#include "nodelist.h"
#include "networkstatus.h"
@@ -1247,6 +1248,239 @@ test_entry_guard_parse_from_state_partial_failure(void *arg)
  tor_free(mem_op_hex_tmp);
}

static int
mock_entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
{
  (void)gs;
  (void)guard;
  return 1;
}

static void
test_entry_guard_parse_from_state_full(void *arg)
{
  (void)arg;
  /* Here's a state I made while testing.  The identities and locations for
   * the bridges are redacted. */
  const char STATE[] =
  "Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
    "nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1\n"
  "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
    "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
    "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
    "pb_successful_circuits_closed=2.000000\n"
  "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
    "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
    "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
    "pb_successful_circuits_closed=5.000000\n"
  "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
    "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1\n"
  "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
    "nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
    "sampled_by=0.3.0.0-alpha-dev listed=1\n"
  "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
    "nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
    "sampled_by=0.3.0.0-alpha-dev listed=1\n"
  "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
    "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
    "sampled_by=0.3.0.0-alpha-dev listed=1 "
    "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
    "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
    "pb_successful_circuits_closed=13.000000\n"
  "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
    "bridge_addr=37.218.246.143:28366 "
    "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n";

  config_line_t *lines = NULL;
  or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
  int r = config_get_lines(STATE, &lines, 0);
  char *msg = NULL;
  smartlist_t *text = smartlist_new();
  char *joined = NULL;

  MOCK(entry_guard_is_listed, mock_entry_guard_is_listed);

  dummy_state = state;
  MOCK(get_or_state,
       get_or_state_replacement);

  tt_assert(r == 0);
  tt_assert(lines);

  state->Guard = lines;

  /* Try it first without setting the result. */
  r = entry_guards_parse_state(state, 0, &msg);
  tt_assert(r == 0);
  guard_selection_t *gs_br =
    get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
  tt_assert(!gs_br);

  r = entry_guards_parse_state(state, 1, &msg);
  tt_assert(r == 0);
  gs_br = get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
  guard_selection_t *gs_df =
    get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
  guard_selection_t *gs_wb =
    get_guard_selection_by_name("wobblesome", GS_TYPE_NORMAL, 0);

  tt_assert(gs_br);
  tt_assert(gs_df);
  tt_assert(gs_wb);

  tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 5);
  tt_int_op(smartlist_len(gs_br->sampled_entry_guards), OP_EQ, 2);
  tt_int_op(smartlist_len(gs_wb->sampled_entry_guards), OP_EQ, 1);

  /* Try again; make sure it doesn't double-add the guards. */
  r = entry_guards_parse_state(state, 1, &msg);
  tt_assert(r == 0);
  gs_br = get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
  gs_df = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
  tt_assert(gs_br);
  tt_assert(gs_df);
  tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 5);
  tt_int_op(smartlist_len(gs_br->sampled_entry_guards), OP_EQ, 2);

  /* Re-encode; it should be the same... almost. */
  {
    /* (Make a guard nonpersistent first) */
    entry_guard_t *g = smartlist_get(gs_df->sampled_entry_guards, 0);
    g->is_persistent = 0;
  }
  config_free_lines(lines);
  lines = state->Guard = NULL; // to prevent double-free.
  entry_guards_update_state(state);
  tt_assert(state->Guard);
  lines = state->Guard;

  config_line_t *ln;
  for (ln = lines; ln; ln = ln->next) {
    smartlist_add_asprintf(text, "%s %s\n",ln->key, ln->value);
  }
  joined = smartlist_join_strings(text, "", 0, NULL);
  tt_str_op(joined, OP_EQ,
  "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
    "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
    "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
    "pb_successful_circuits_closed=2.000000\n"
  "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
    "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=1 "
    "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
    "pb_successful_circuits_closed=5.000000\n"
  "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
    "nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
    "sampled_by=0.3.0.0-alpha-dev listed=1\n"
  "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
    "nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
    "sampled_by=0.3.0.0-alpha-dev listed=1\n"
  "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
    "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1\n"
  "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
    "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
    "sampled_by=0.3.0.0-alpha-dev listed=1 "
    "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
    "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
    "pb_successful_circuits_closed=13.000000\n"
  "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
    "bridge_addr=37.218.246.143:28366 "
    "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n");

 done:
  config_free_lines(lines);
  tor_free(state);
  tor_free(msg);
  UNMOCK(get_or_state);
  UNMOCK(entry_guard_is_listed);
  SMARTLIST_FOREACH(text, char *, cp, tor_free(cp));
  smartlist_free(text);
  tor_free(joined);
}

static void
test_entry_guard_parse_from_state_broken(void *arg)
{
  (void)arg;
  /* Here's a variation on the previous state. Every line but the first is
   * busted somehow. */
  const char STATE[] =
  /* Okay. */
  "Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
    "nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1\n"
  /* No selection listed. */
  "Guard rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
    "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
    "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
    "pb_successful_circuits_closed=2.000000\n"
  /* Selection is "legacy"!! */
  "Guard in=legacy rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
    "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
    "sampled_by=0.3.0.0-alpha-dev "
    "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
    "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
    "pb_successful_circuits_closed=5.000000\n";

  config_line_t *lines = NULL;
  or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
  int r = config_get_lines(STATE, &lines, 0);
  char *msg = NULL;

  dummy_state = state;
  MOCK(get_or_state,
       get_or_state_replacement);

  tt_assert(r == 0);
  tt_assert(lines);

  state->Guard = lines;

  /* First, no-set case. we should get an error. */
  r = entry_guards_parse_state(state, 0, &msg);
  tt_int_op(r, OP_LT, 0);
  tt_ptr_op(msg, OP_NE, NULL);
  /* And we shouldn't have made anything. */
  guard_selection_t *gs_df =
    get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
  tt_assert(gs_df == NULL);
  tor_free(msg);

  /* Now see about the set case (which shouldn't happen IRL) */
  r = entry_guards_parse_state(state, 1, &msg);
  tt_int_op(r, OP_LT, 0);
  tt_ptr_op(msg, OP_NE, NULL);
  gs_df = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
  tt_assert(gs_df != NULL);
  tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 1);
  guard_selection_t *gs_legacy =
    get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 0);
  tt_assert(gs_legacy != NULL);
  tt_int_op(smartlist_len(gs_legacy->chosen_entry_guards), OP_EQ, 0);

 done:
  config_free_lines(lines);
  tor_free(state);
  tor_free(msg);
  UNMOCK(get_or_state);
}

static void
test_entry_guard_get_guard_selection_by_name(void *arg)
{
@@ -3019,6 +3253,10 @@ struct testcase_t entrynodes_tests[] = {
    test_entry_guard_parse_from_state_failure, 0, NULL, NULL },
  { "parse_from_state_partial_failure",
    test_entry_guard_parse_from_state_partial_failure, 0, NULL, NULL },
  { "parse_from_state_full",
    test_entry_guard_parse_from_state_full, TT_FORK, NULL, NULL },
  { "parse_from_state_broken",
    test_entry_guard_parse_from_state_broken, TT_FORK, NULL, NULL },
  { "get_guard_selection_by_name",
    test_entry_guard_get_guard_selection_by_name, TT_FORK, NULL, NULL },
  BFN_TEST(add_single_guard),