diff --git a/src/test/include.am b/src/test/include.am index 294b9f309c..667bbf5368 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -123,6 +123,7 @@ src_test_test_SOURCES += \ src/test/test_checkdir.c \ src/test/test_circuitlist.c \ src/test/test_circuitmux.c \ + src/test/test_circuitmux_ewma.c \ src/test/test_circuitbuild.c \ src/test/test_circuituse.c \ src/test/test_circuitstats.c \ diff --git a/src/test/test.c b/src/test/test.c index 6dbec26fa8..c4227dca50 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -836,6 +836,7 @@ struct testgroup_t testgroups[] = { { "circuitpadding/", circuitpadding_tests }, { "circuitlist/", circuitlist_tests }, { "circuitmux/", circuitmux_tests }, + { "circuitmux_ewma/", circuitmux_ewma_tests }, { "circuitstats/", circuitstats_tests }, { "circuituse/", circuituse_tests }, { "compat/libevent/", compat_libevent_tests }, diff --git a/src/test/test.h b/src/test/test.h index feaa13a3a5..b2dc552c82 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -199,6 +199,7 @@ extern struct testcase_t checkdir_tests[]; extern struct testcase_t circuitbuild_tests[]; extern struct testcase_t circuitlist_tests[]; extern struct testcase_t circuitmux_tests[]; +extern struct testcase_t circuitmux_ewma_tests[]; extern struct testcase_t circuitstats_tests[]; extern struct testcase_t circuituse_tests[]; extern struct testcase_t compat_libevent_tests[]; diff --git a/src/test/test_circuitmux_ewma.c b/src/test/test_circuitmux_ewma.c new file mode 100644 index 0000000000..8b3edf2b06 --- /dev/null +++ b/src/test/test_circuitmux_ewma.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2013-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CIRCUITMUX_PRIVATE +#define CIRCUITMUX_EWMA_PRIVATE + +#include "core/or/or.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" + +#include "test/fakechans.h" +#include "test/fakecircs.h" +#include "test/test.h" + +static void +test_cmux_ewma_active_circuit(void *arg) +{ + circuitmux_t cmux; /* garbage */ + circuitmux_policy_data_t *pol_data = NULL; + circuit_t circ; /* garbage */ + circuitmux_policy_circ_data_t *circ_data = NULL; + + (void) arg; + + pol_data = ewma_policy.alloc_cmux_data(&cmux); + tt_assert(pol_data); + circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ, + CELL_DIRECTION_OUT, 42); + tt_assert(circ_data); + + /* Get EWMA specific objects. */ + + /* Make circuit active. */ + ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data); + + circuit_t *entry = ewma_policy.pick_active_circuit(&cmux, pol_data); + tt_mem_op(entry, OP_EQ, &circ, sizeof(circ)); + + done: + ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data); + ewma_policy.free_cmux_data(&cmux, pol_data); +} + +static void +test_cmux_ewma_xmit_cell(void *arg) +{ + circuitmux_t cmux; /* garbage */ + circuitmux_policy_data_t *pol_data = NULL; + circuit_t circ; /* garbage */ + circuitmux_policy_circ_data_t *circ_data = NULL; + ewma_policy_data_t *ewma_pol_data; + ewma_policy_circ_data_t *ewma_data; + double old_cell_count; + + (void) arg; + + pol_data = ewma_policy.alloc_cmux_data(&cmux); + tt_assert(pol_data); + circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ, + CELL_DIRECTION_OUT, 42); + tt_assert(circ_data); + ewma_pol_data = TO_EWMA_POL_DATA(pol_data); + ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data); + + /* Make circuit active. */ + ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data); + + /* Move back in time the last time we calibrated so we scale the active + * circuit when emitting a cell. */ + ewma_pol_data->active_circuit_pqueue_last_recalibrated -= 100; + ewma_data->cell_ewma.last_adjusted_tick = + ewma_pol_data->active_circuit_pqueue_last_recalibrated; + + /* Grab old cell count. */ + old_cell_count = ewma_data->cell_ewma.cell_count; + + ewma_policy.notify_xmit_cells(&cmux, pol_data, &circ, circ_data, 1); + + /* Our old cell count should be lower to what we have since we just emitted + * a cell and thus we scale. */ + tt_double_op(old_cell_count, OP_LT, ewma_data->cell_ewma.cell_count); + + done: + ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data); + ewma_policy.free_cmux_data(&cmux, pol_data); +} + +static void +test_cmux_ewma_notify_circ(void *arg) +{ + circuitmux_t cmux; /* garbage */ + circuitmux_policy_data_t *pol_data = NULL; + circuit_t circ; /* garbage */ + circuitmux_policy_circ_data_t *circ_data = NULL; + const ewma_policy_data_t *ewma_pol_data; + + (void) arg; + + pol_data = ewma_policy.alloc_cmux_data(&cmux); + tt_assert(pol_data); + circ_data = ewma_policy.alloc_circ_data(&cmux, pol_data, &circ, + CELL_DIRECTION_OUT, 42); + tt_assert(circ_data); + + /* Currently, notify_circ_active() ignores cmux and circ. They can not be + * NULL so it is fine to pass garbage. */ + ewma_policy.notify_circ_active(&cmux, pol_data, &circ, circ_data); + + /* We should have an active circuit in the queue so its EWMA value can be + * tracked. */ + ewma_pol_data = TO_EWMA_POL_DATA(pol_data); + tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 1); + tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0); + + ewma_policy.notify_circ_inactive(&cmux, pol_data, &circ, circ_data); + /* Should be removed from the active queue. */ + ewma_pol_data = TO_EWMA_POL_DATA(pol_data); + tt_int_op(smartlist_len(ewma_pol_data->active_circuit_pqueue), OP_EQ, 0); + tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0); + + done: + ewma_policy.free_circ_data(&cmux, pol_data, &circ, circ_data); + ewma_policy.free_cmux_data(&cmux, pol_data); +} + +static void +test_cmux_ewma_policy_circ_data(void *arg) +{ + circuitmux_t cmux; /* garbage */ + circuitmux_policy_data_t pol_data; /* garbage */ + circuit_t circ; /* garbage */ + circuitmux_policy_circ_data_t *circ_data = NULL; + const ewma_policy_circ_data_t *ewma_data; + + (void) arg; + + /* Currently, alloc_circ_data() ignores every parameter _except_ the cell + * direction so it is OK to pass garbage. They can not be NULL. */ + circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ, + CELL_DIRECTION_OUT, 42); + tt_assert(circ_data); + tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC); + + ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data); + tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t)); + tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0); + tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1); + tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 0); + ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data); + + circ_data = ewma_policy.alloc_circ_data(&cmux, &pol_data, &circ, + CELL_DIRECTION_IN, 42); + tt_assert(circ_data); + tt_uint_op(circ_data->magic, OP_EQ, EWMA_POL_CIRC_DATA_MAGIC); + + ewma_data = TO_EWMA_POL_CIRC_DATA(circ_data); + tt_mem_op(ewma_data->circ, OP_EQ, &circ, sizeof(circuit_t)); + tt_double_op(ewma_data->cell_ewma.cell_count, OP_LE, 0.0); + tt_int_op(ewma_data->cell_ewma.heap_index, OP_EQ, -1); + tt_uint_op(ewma_data->cell_ewma.is_for_p_chan, OP_EQ, 1); + + done: + ewma_policy.free_circ_data(&cmux, &pol_data, &circ, circ_data); +} + +static void +test_cmux_ewma_policy_data(void *arg) +{ + circuitmux_t cmux; /* garbage. */ + circuitmux_policy_data_t *pol_data = NULL; + const ewma_policy_data_t *ewma_pol_data; + + (void) arg; + + pol_data = ewma_policy.alloc_cmux_data(&cmux); + tt_assert(pol_data); + tt_uint_op(pol_data->magic, OP_EQ, EWMA_POL_DATA_MAGIC); + + /* Test EWMA object. */ + ewma_pol_data = TO_EWMA_POL_DATA(pol_data); + tt_assert(ewma_pol_data->active_circuit_pqueue); + tt_uint_op(ewma_pol_data->active_circuit_pqueue_last_recalibrated, OP_NE, 0); + + done: + ewma_policy.free_cmux_data(&cmux, pol_data); +} + +static void * +cmux_ewma_setup_test(const struct testcase_t *tc) +{ + static int whatever; + + (void) tc; + + cell_ewma_initialize_ticks(); + cmux_ewma_set_options(NULL, NULL); + + return &whatever; +} + +static int +cmux_ewma_cleanup_test(const struct testcase_t *tc, void *ptr) +{ + (void) tc; + (void) ptr; + + circuitmux_ewma_free_all(); + + return 1; +} + +static struct testcase_setup_t cmux_ewma_test_setup = { + .setup_fn = cmux_ewma_setup_test, + .cleanup_fn = cmux_ewma_cleanup_test, +}; + +#define TEST_CMUX_EWMA(name) \ + { #name, test_cmux_ewma_##name, TT_FORK, &cmux_ewma_test_setup, NULL } + +struct testcase_t circuitmux_ewma_tests[] = { + TEST_CMUX_EWMA(active_circuit), + TEST_CMUX_EWMA(policy_data), + TEST_CMUX_EWMA(policy_circ_data), + TEST_CMUX_EWMA(notify_circ), + TEST_CMUX_EWMA(xmit_cell), + + END_OF_TESTCASES +};