Add scheduler channel states unit test

This commit is contained in:
Andrea Shepard 2014-01-28 17:34:16 -08:00
parent dc3af04ba8
commit 684bcd886a

View File

@ -41,6 +41,8 @@ static circuitmux_t *mock_cgp_tgt_1 = NULL;
static const circuitmux_policy_t *mock_cgp_val_1 = NULL;
static circuitmux_t *mock_cgp_tgt_2 = NULL;
static const circuitmux_policy_t *mock_cgp_val_2 = NULL;
static int scheduler_compare_channels_mock_ctr = 0;
static int scheduler_run_mock_ctr = 0;
/* Setup for mock event stuff */
static void mock_event_free_all(void);
@ -51,9 +53,13 @@ static int circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
circuitmux_t *cmux_2);
static const circuitmux_policy_t * circuitmux_get_policy_mock(
circuitmux_t *cmux);
static int scheduler_compare_channels_mock(const void *c1_v,
const void *c2_v);
static void scheduler_run_noop_mock(void);
static struct event_base * tor_libevent_get_base_mock(void);
/* Scheduler test cases */
static void test_scheduler_channel_states(void *arg);
static void test_scheduler_compare_channels(void *arg);
static void test_scheduler_initfree(void *arg);
static void test_scheduler_queue_heuristic(void *arg);
@ -130,8 +136,7 @@ circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
if (cmux_1 == mock_ccm_tgt_1 && cmux_2 == mock_ccm_tgt_2) result = -1;
else if (cmux_1 == mock_ccm_tgt_2 && cmux_2 == mock_ccm_tgt_1) {
result = 1;
}
else {
} else {
if (cmux_1 == mock_ccm_tgt_1 || cmux_1 == mock_ccm_tgt_1) result = -1;
else if (cmux_2 == mock_ccm_tgt_1 || cmux_2 == mock_ccm_tgt_2) {
result = 1;
@ -162,6 +167,28 @@ circuitmux_get_policy_mock(circuitmux_t *cmux)
return result;
}
static int
scheduler_compare_channels_mock(const void *c1_v,
const void *c2_v)
{
uintptr_t p1, p2;
p1 = (uintptr_t)(c1_v);
p2 = (uintptr_t)(c2_v);
++scheduler_compare_channels_mock_ctr;
if (p1 == p2) return 0;
else if (p1 < p2) return 1;
else return -1;
}
static void
scheduler_run_noop_mock(void)
{
++scheduler_run_mock_ctr;
}
static struct event_base *
tor_libevent_get_base_mock(void)
{
@ -170,6 +197,125 @@ tor_libevent_get_base_mock(void)
/* Test cases */
static void
test_scheduler_channel_states(void *arg)
{
channel_t *ch1 = NULL, *ch2 = NULL;
int old_count;
(void)arg;
/* Set up libevent and scheduler */
mock_event_init();
MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
scheduler_init();
/*
* Install the compare channels mock so we can test
* scheduler_touch_channel().
*/
MOCK(scheduler_compare_channels, scheduler_compare_channels_mock);
/*
* Disable scheduler_run so we can just check the state transitions
* without having to make everything it might call work too.
*/
MOCK(scheduler_run, scheduler_run_noop_mock);
test_eq(smartlist_len(channels_pending), 0);
/* Set up a fake channel */
ch1 = new_fake_channel();
test_assert(ch1);
/* Start it off in OPENING */
ch1->state = CHANNEL_STATE_OPENING;
/* We'll need a cmux */
ch1->cmux = circuitmux_alloc();
/* Try to register it */
channel_register(ch1);
test_assert(ch1->registered);
/* It should start off in SCHED_CHAN_IDLE */
test_eq(ch1->scheduler_state, SCHED_CHAN_IDLE);
/* Now get another one */
ch2 = new_fake_channel();
test_assert(ch2);
ch2->state = CHANNEL_STATE_OPENING;
ch2->cmux = circuitmux_alloc();
channel_register(ch2);
test_assert(ch2->registered);
/* Send it to SCHED_CHAN_WAITING_TO_WRITE */
scheduler_channel_has_waiting_cells(ch1);
test_eq(ch1->scheduler_state, SCHED_CHAN_WAITING_TO_WRITE);
/* This should send it to SCHED_CHAN_PENDING */
scheduler_channel_wants_writes(ch1);
test_eq(ch1->scheduler_state, SCHED_CHAN_PENDING);
test_eq(smartlist_len(channels_pending), 1);
/* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_WAITING_FOR_CELLS);
/* Drop ch2 back to idle */
scheduler_channel_doesnt_want_writes(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_IDLE);
/* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_WAITING_FOR_CELLS);
/* ...and this should kick ch2 into SCHED_CHAN_PENDING */
scheduler_channel_has_waiting_cells(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_PENDING);
test_eq(smartlist_len(channels_pending), 2);
/* This should send ch2 to SCHED_CHAN_WAITING_TO_WRITE */
scheduler_channel_doesnt_want_writes(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_WAITING_TO_WRITE);
test_eq(smartlist_len(channels_pending), 1);
/* ...and back to SCHED_CHAN_PENDING */
scheduler_channel_wants_writes(ch2);
test_eq(ch2->scheduler_state, SCHED_CHAN_PENDING);
test_eq(smartlist_len(channels_pending), 2);
/* Now we exercise scheduler_touch_channel */
old_count = scheduler_compare_channels_mock_ctr;
scheduler_touch_channel(ch1);
test_assert(scheduler_compare_channels_mock_ctr > old_count);
/* Close */
channel_mark_for_close(ch1);
test_eq(ch1->state, CHANNEL_STATE_CLOSING);
channel_mark_for_close(ch2);
test_eq(ch2->state, CHANNEL_STATE_CLOSING);
channel_closed(ch1);
test_eq(ch1->state, CHANNEL_STATE_CLOSED);
ch1 = NULL;
channel_closed(ch2);
test_eq(ch2->state, CHANNEL_STATE_CLOSED);
ch2 = NULL;
/* Shut things down */
channel_free_all();
scheduler_free_all();
mock_event_free_all();
done:
tor_free(ch1);
tor_free(ch2);
UNMOCK(scheduler_compare_channels);
UNMOCK(scheduler_run);
UNMOCK(tor_libevent_get_base);
return;
}
static void
test_scheduler_compare_channels(void *arg)
{
@ -208,7 +354,7 @@ test_scheduler_compare_channels(void *arg)
/* Equal-channel case */
result = scheduler_compare_channels(&c1, &c1);
test_eq(result, 0);
/* Distinct channels, distinct policies */
result = scheduler_compare_channels(&c1, &c2);
test_eq(result, -1);
@ -303,6 +449,7 @@ test_scheduler_queue_heuristic(void *arg)
}
struct testcase_t scheduler_tests[] = {
{ "channel_states", test_scheduler_channel_states, TT_FORK, NULL, NULL },
{ "compare_channels", test_scheduler_compare_channels,
TT_FORK, NULL, NULL },
{ "initfree", test_scheduler_initfree, TT_FORK, NULL, NULL },