commit 684bcd886abb36414a1499ced1b038050f6face1
Author: Andrea Shepard <andrea(a)torproject.org>
Date: Tue Jan 28 17:34:16 2014 -0800
Add scheduler channel states unit test
---
src/test/test_scheduler.c | 153 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 150 insertions(+), 3 deletions(-)
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index e40df16..650d4f1 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -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)
{
@@ -171,6 +198,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)
{
/* We don't actually need whole fake channels... */
@@ -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 },