/* Copyright (c) 2013-2020, 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 };