mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Add scheduler channel states unit test
This commit is contained in:
parent
dc3af04ba8
commit
684bcd886a
@ -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 },
|
||||
|
Loading…
Reference in New Issue
Block a user