From 2b44dccaaf632794b22e8e0e3e407702b1719851 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 13 May 2010 12:01:30 -0400 Subject: [PATCH] Add options to test-ratelim.c to check its results The new options let you specify a maximum deviation of bandwidth used from expected bandwidth used, and make test-ratelim.c exit with a nonzero status when those deviations are violated. This patch also adds a test-ratelim.sh script to run test-ratelim with a few sensible options for testing. --- test/test-ratelim.c | 67 ++++++++++++++++++++++++++++++++++++------- test/test-ratelim.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 10 deletions(-) create mode 100755 test/test-ratelim.sh diff --git a/test/test-ratelim.c b/test/test-ratelim.c index 21715e3a..c0c8c23f 100644 --- a/test/test-ratelim.c +++ b/test/test-ratelim.c @@ -54,11 +54,16 @@ static int cfg_connlimit = 0; static int cfg_grouplimit = 0; static int cfg_tick_msec = 1000; +static int cfg_connlimit_tolerance = -1; +static int cfg_grouplimit_tolerance = -1; +static int cfg_stddev_tolerance = -1; + static struct timeval cfg_tick = { 0, 500*1000 }; static struct ev_token_bucket_cfg *conn_bucket_cfg = NULL; static struct ev_token_bucket_cfg *group_bucket_cfg = NULL; struct bufferevent_rate_limit_group *ratelim_group = NULL; +static double seconds_per_tick = 0.0; struct client_state { size_t queued; @@ -131,7 +136,7 @@ echo_listenercb(struct evconnlistener *listener, evutil_socket_t newsock, bufferevent_enable(bev, EV_READ|EV_WRITE); } -static void +static int test_ratelimiting(void) { struct event_base *base; @@ -151,6 +156,8 @@ test_ratelimiting(void) ev_uint64_t total_received; double total_sq_persec, total_persec; double variance; + double expected_total_persec = -1.0, expected_avg_persec = -1.0; + int ok = 1; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; @@ -166,7 +173,7 @@ test_ratelimiting(void) if (getsockname(evconnlistener_get_fd(listener), (struct sockaddr *)&ss, &slen) < 0) { perror("getsockname"); - return; + return 1; } if (cfg_connlimit > 0) { @@ -184,7 +191,19 @@ test_ratelimiting(void) &cfg_tick); ratelim_group = bufferevent_rate_limit_group_new( base, group_bucket_cfg); - }; + expected_total_persec = cfg_grouplimit; + expected_avg_persec = cfg_grouplimit / cfg_n_connections; + if (cfg_connlimit > 0 && expected_avg_persec > cfg_connlimit) + expected_avg_persec = cfg_connlimit; + } + + if (expected_avg_persec < 0 && cfg_connlimit > 0) + expected_avg_persec = cfg_connlimit; + + if (expected_avg_persec > 0) + expected_avg_persec /= seconds_per_tick; + if (expected_total_persec > 0) + expected_total_persec /= seconds_per_tick; bevs = calloc(cfg_n_connections, sizeof(struct bufferevent *)); states = calloc(cfg_n_connections, sizeof(struct client_state)); @@ -200,8 +219,8 @@ test_ratelimiting(void) slen); } - tv.tv_sec = cfg_duration; - tv.tv_usec = 0; + tv.tv_sec = cfg_duration - 1; + tv.tv_usec = 995000; event_base_loopexit(base, &tv); @@ -216,16 +235,43 @@ test_ratelimiting(void) total_received += states[i].received; total_persec += persec; total_sq_persec += persec*persec; - printf("%d: %f per second\n", i, persec); + printf("%d: %f per second\n", i+1, persec); } printf(" total: %f per second\n", ((double)total_received)/cfg_duration); + if (expected_total_persec > 0) { + double diff = expected_total_persec - + ((double)total_received/cfg_duration); + printf(" [Off by %lf]\n", diff); + if (cfg_grouplimit_tolerance > 0 && + fabs(diff) > cfg_grouplimit_tolerance) { + fprintf(stderr, "Group bandwidth out of bounds\n"); + ok = 0; + } + } + printf(" average: %f per second\n", (((double)total_received)/cfg_duration)/cfg_n_connections); + if (expected_avg_persec > 0) { + double diff = expected_avg_persec - (((double)total_received)/cfg_duration)/cfg_n_connections; + printf(" [Off by %lf]\n", diff); + if (cfg_connlimit_tolerance > 0 && + fabs(diff) > cfg_connlimit_tolerance) { + fprintf(stderr, "Connection bandwidth out of bounds\n"); + ok = 0; + } + } variance = total_sq_persec/cfg_n_connections - total_persec*total_persec/(cfg_n_connections*cfg_n_connections); printf(" stddev: %f per second\n", sqrt(variance)); + if (cfg_stddev_tolerance > 0 && + sqrt(variance) > cfg_stddev_tolerance) { + fprintf(stderr, "Connection variance out of bounds\n"); + ok = 0; + } + + return ok ? 0 : 1; } static struct option { @@ -238,6 +284,9 @@ static struct option { { "-c", &cfg_connlimit, 0, 0 }, { "-g", &cfg_grouplimit, 0, 0 }, { "-t", &cfg_tick_msec, 10, 0 }, + { "--check-connlimit", &cfg_connlimit_tolerance, 0, 0 }, + { "--check-grouplimit", &cfg_grouplimit_tolerance, 0, 0 }, + { "--check-stddev", &cfg_stddev_tolerance, 0, 0 }, { NULL, NULL, -1, 0 }, }; @@ -324,7 +373,7 @@ main(int argc, char **argv) cfg_tick.tv_sec = cfg_tick_msec / 1000; cfg_tick.tv_usec = (cfg_tick_msec % 1000)*1000; - ratio = cfg_tick_msec / 1000.0; + seconds_per_tick = ratio = cfg_tick_msec / 1000.0; cfg_connlimit *= ratio; cfg_grouplimit *= ratio; @@ -343,7 +392,5 @@ main(int argc, char **argv) evthread_enable_lock_debuging(); #endif - test_ratelimiting(); - - return 0; + return test_ratelimiting(); } diff --git a/test/test-ratelim.sh b/test/test-ratelim.sh new file mode 100755 index 00000000..201794c4 --- /dev/null +++ b/test/test-ratelim.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +if test "x$TEST_OUTPUT_FILE" = "x" +then + TEST_OUTPUT_FILE=/dev/null +fi + +# /bin/echo is a little more likely to support -n than sh's builtin echo. +if test -x /bin/echo +then + ECHO=/bin/echo +else + ECHO=echo +fi + +if test "$TEST_OUTPUT_FILE" != "/dev/null" +then + touch "$TEST_OUTPUT_FILE" || exit 1 +fi + +TEST_DIR=. + +T=`echo "$0" | sed -e 's/test-ratelim.sh$//'` +if test -x "$T/test-ratelim" +then + TEST_DIR="$T" +fi + +announce () { + echo $@ + echo $@ >>"$TEST_OUTPUT_FILE" +} + +announce_n () { + $ECHO -n $@ + echo $@ >>"$TEST_OUTPUT_FILE" +} + + +run_tests () { + announce_n " Group limits, no connection limit:" + if $TEST_DIR/test-ratelim -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-stddev 100 >>"$TEST_OUTPUT_FILE" + then + announce OKAY + else + announce FAILED + fi + + announce_n " Connection limit, no group limit:" + if $TEST_DIR/test-ratelim -c 1000 -n 30 -t 100 --check-connlimit 50 --check-stddev 50 >>"$TEST_OUTPUT_FILE" + then + announce OKAY ; + else + announce FAILED ; + fi + + announce_n " Connection limit and group limit:" + if $TEST_DIR/test-ratelim -c 1000 -g 30000 -n 30 -t 100 --check-grouplimit 1000 --check-connlimit 50 --check-stddev 50 >>"$TEST_OUTPUT_FILE" + then + announce OKAY ; + else + announce FAILED ; + fi +} + +announce "Running rate-limiting tests:" + +run_tests -- 2.40.0