From f7fc48a2bab0c4cae8fe9f9d9a26ff5dd3b63bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 29 Sep 2022 10:45:15 +0200 Subject: [PATCH] Add isc_ratelimiter API unit tests The isc_ratelimiter API was missing unit tests. Add a new set of unit tests for the isc_ratelimiter API. --- tests/isc/Makefile.am | 1 + tests/isc/ratelimiter_test.c | 334 +++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 tests/isc/ratelimiter_test.c diff --git a/tests/isc/Makefile.am b/tests/isc/Makefile.am index a9fd5a6137..e6a5d46ac0 100644 --- a/tests/isc/Makefile.am +++ b/tests/isc/Makefile.am @@ -32,6 +32,7 @@ check_PROGRAMS = \ quota_test \ radix_test \ random_test \ + ratelimiter_test\ regex_test \ result_test \ safe_test \ diff --git a/tests/isc/ratelimiter_test.c b/tests/isc/ratelimiter_test.c new file mode 100644 index 0000000000..7f82f3088a --- /dev/null +++ b/tests/isc/ratelimiter_test.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include /* IWYU pragma: keep */ +#include +#include +#include +#include +#include +#include + +#define UNIT_TESTING +#include + +#include +#include +#include +#include +#include + +#include "ratelimiter.c" + +#include + +#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ + +isc_ratelimiter_t *rl = NULL; + +ISC_LOOP_TEST_IMPL(ratelimiter_create) { + rl = NULL; + expect_assert_failure(isc_ratelimiter_create(NULL, &rl)); + expect_assert_failure(isc_ratelimiter_create(mainloop, NULL)); + rl = (isc_ratelimiter_t *)&rl; + expect_assert_failure(isc_ratelimiter_create(mainloop, &rl)); + + rl = NULL; + isc_ratelimiter_create(mainloop, &rl); + isc_ratelimiter_shutdown(rl); + + isc_ratelimiter_detach(&rl); + + isc_loopmgr_shutdown(loopmgr); +} + +ISC_LOOP_TEST_IMPL(ratelimiter_shutdown) { + rl = NULL; + + expect_assert_failure(isc_ratelimiter_shutdown(NULL)); + expect_assert_failure(isc_ratelimiter_shutdown(rl)); + + isc_loopmgr_shutdown(loopmgr); +} + +ISC_LOOP_TEST_IMPL(ratelimiter_detach) { + rl = NULL; + + expect_assert_failure(isc_ratelimiter_detach(NULL)); + expect_assert_failure(isc_ratelimiter_detach(&rl)); + + isc_loopmgr_shutdown(loopmgr); +} + +static int ticks = 0; +static isc_task_t *rl_task = NULL; +static isc_time_t start_time; +static isc_time_t tick_time; + +static void +tick(isc_task_t *task, isc_event_t *event) { + assert_ptr_equal(task, rl_task); + isc_event_free(&event); + + ticks++; + + assert_int_equal(isc_time_now(&tick_time), ISC_R_SUCCESS); + + isc_loopmgr_shutdown(loopmgr); + + isc_task_detach(&rl_task); + isc_ratelimiter_shutdown(rl); + isc_ratelimiter_detach(&rl); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_common) { + isc_result_t result = isc_task_create(taskmgr, &rl_task, 0); + assert_int_equal(result, ISC_R_SUCCESS); + + rl = NULL; + isc_time_set(&tick_time, 0, 0); + assert_int_equal(isc_time_now(&start_time), ISC_R_SUCCESS); + isc_ratelimiter_create(mainloop, &rl); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_enqueue) { + ticks = 0; + setup_loop_ratelimiter_common(arg); +} + +ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue) { assert_int_equal(ticks, 1); } + +ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue) { + isc_result_t result; + isc_event_t *event = NULL; + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + result = isc_ratelimiter_enqueue(rl, rl_task, &event); + assert_int_equal(result, ISC_R_SUCCESS); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_enqueue_shutdown) { + ticks = 0; + setup_loop_ratelimiter_common(arg); +} + +ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) { + assert_int_equal(ticks, 1); +} + +ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) { + isc_event_t *event = NULL; + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + expect_assert_failure(isc_ratelimiter_enqueue(NULL, rl_task, &event)); + expect_assert_failure(isc_ratelimiter_enqueue(rl, NULL, &event)); + expect_assert_failure(isc_ratelimiter_enqueue(rl, rl_task, NULL)); + expect_assert_failure( + isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ NULL })); + + assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + ISC_R_SUCCESS); + + isc_ratelimiter_shutdown(rl); + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + ISC_R_SHUTTINGDOWN); + + isc_event_free(&event); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_dequeue) { + ticks = 0; + setup_loop_ratelimiter_common(arg); +} + +ISC_LOOP_TEARDOWN_IMPL(ratelimiter_dequeue) { /* */ + assert_int_equal(ticks, 1); +} + +ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_dequeue) { + isc_event_t *event = NULL; + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + assert_int_equal( + isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), + ISC_R_SUCCESS); + assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_SUCCESS); + isc_event_free(&event); + assert_null(event); + + /* This event didn't get scheduled */ + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_NOTFOUND); + assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + ISC_R_SUCCESS); + assert_null(event); +} + +static isc_time_t tock_time; + +static void +tock(isc_task_t *task, isc_event_t *event) { + assert_ptr_equal(task, rl_task); + isc_event_free(&event); + + ticks++; + assert_int_equal(isc_time_now(&tock_time), ISC_R_SUCCESS); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_pertick_interval) { + ticks = 0; + isc_time_set(&tock_time, 0, 0); + setup_loop_ratelimiter_common(arg); +} + +ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pertick_interval) { + uint64_t t = isc_time_microdiff(&tick_time, &tock_time); + assert_int_equal(ticks, 2); + assert_true(t >= 1000000); + + t = isc_time_microdiff(&tock_time, &start_time); + assert_true(t < 1000000); +} + +ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pertick_interval) { + isc_event_t *event = NULL; + isc_interval_t interval; + + isc_interval_set(&interval, 1, NS_PER_S / 10); + + expect_assert_failure(isc_ratelimiter_setinterval(NULL, &interval)); + expect_assert_failure(isc_ratelimiter_setinterval(rl, NULL)); + expect_assert_failure(isc_ratelimiter_setpertic(NULL, 1)); + expect_assert_failure(isc_ratelimiter_setpertic(rl, 0)); + expect_assert_failure(isc_ratelimiter_setpushpop(NULL, false)); + + isc_ratelimiter_setinterval(rl, &interval); + isc_ratelimiter_setpertic(rl, 1); + isc_ratelimiter_setpushpop(rl, false); + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + ISC_R_SUCCESS); + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event), + ISC_R_SUCCESS); +} + +ISC_LOOP_SETUP_IMPL(ratelimiter_pushpop) { + ticks = 0; + isc_time_set(&tock_time, 0, 0); + setup_loop_ratelimiter_common(arg); +} + +ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pushpop) { + uint64_t t = isc_time_microdiff(&tock_time, &tick_time); + assert_int_equal(ticks, 2); + assert_true(t < 1000000); +} + +ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pushpop) { + isc_event_t *event = NULL; + isc_interval_t interval; + + isc_interval_set(&interval, 1, NS_PER_S / 10); + + isc_ratelimiter_setinterval(rl, &interval); + isc_ratelimiter_setpertic(rl, 2); + isc_ratelimiter_setpushpop(rl, true); + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + assert_int_equal( + isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), + ISC_R_SUCCESS); + + event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL, + sizeof(isc_event_t)); + assert_non_null(event); + + assert_int_equal( + isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }), + ISC_R_SUCCESS); +} + +static int +setup_test(void **state) { + int r; + + r = setup_loopmgr(state); + if (r != 0) { + return (r); + } + r = setup_taskmgr(state); + if (r != 0) { + return (r); + } + + return (0); +} + +static int +teardown_test(void **state) { + int r; + + r = teardown_taskmgr(state); + if (r != 0) { + return (r); + } + r = teardown_loopmgr(state); + if (r != 0) { + return (r); + } + + return (0); +} + +ISC_TEST_LIST_START + +ISC_TEST_ENTRY_CUSTOM(ratelimiter_create, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_shutdown, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_detach, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_enqueue, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_enqueue_shutdown, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_dequeue, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_pertick_interval, setup_test, teardown_test) +ISC_TEST_ENTRY_CUSTOM(ratelimiter_pushpop, setup_test, teardown_test) + +ISC_TEST_LIST_END + +ISC_TEST_MAIN