diff options
Diffstat (limited to 'src/lib/test-event-category-register.c')
-rw-r--r-- | src/lib/test-event-category-register.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/lib/test-event-category-register.c b/src/lib/test-event-category-register.c new file mode 100644 index 0000000..50cc038 --- /dev/null +++ b/src/lib/test-event-category-register.c @@ -0,0 +1,320 @@ +/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "ioloop.h" +#include "time-util.h" +#include "lib-event-private.h" +#include "failures-private.h" + +/* we call a generic "unregister category function; to tell it what exact + * behavior it should expect from lib-lib, we pass in one of the following + * values + */ +enum unreg_expectation { + UNREG_NOT_LAST, + UNREG_LAST, + UNREG_NOP, +}; + +#define CAT_NAME_PREFIX "test-category" + +/* pointer to a category we expect to be registered/unregistered */ +static struct event_category *expected_callback_cat; +static bool callback_called; + +static struct event *dummy_event; + +static void check_category(struct event_category *cat) +{ + callback_called = TRUE; + + /* lib-lib called a callback with a NULL? (useless and a bug) */ + test_assert(cat != NULL); + + /* callback called, but didn't expect to be called? */ + test_assert(expected_callback_cat != NULL); + + /* test_assert() doesn't terminate, so avoid NULL ptr derefs later on */ + if ((cat == NULL) || (expected_callback_cat == NULL)) + return; + + /* check that the categories have the same values */ + test_assert(strcmp(cat->name, expected_callback_cat->name) == 0); + test_assert(cat->internal == expected_callback_cat->internal); +} + +static void check_cat_registered(const char *name, bool should_exist) +{ + struct event_category *cat; + + callback_called = FALSE; + cat = event_category_find_registered(name); + test_assert(callback_called == FALSE); + + test_assert((cat != NULL) == should_exist); +} + +static void register_cat(struct event_category *newcat, + struct event_category *expcat) +{ + /* start with a known state - no regs expected */ + expected_callback_cat = NULL; + callback_called = FALSE; + + dummy_event = event_create(NULL); + test_assert(callback_called == FALSE); + + /* we expect a registration only when adding a cat */ + expected_callback_cat = (expcat); + event_add_category(dummy_event, (newcat)); + expected_callback_cat = NULL; + + /* check that all went well */ + test_assert(callback_called == (expcat != NULL)); + test_assert((newcat)->internal != NULL); + test_assert(event_category_find_registered((newcat)->name) != NULL); + + /* clean up */ + event_unref(&dummy_event); +} + +static void unregister_cat(struct event_category *cat, + enum unreg_expectation expectation) +{ + /* sanity check that cat is set up as expected */ + switch (expectation) { + case UNREG_NOT_LAST: + /* must be registered to unregister */ + test_assert(event_category_find_registered((cat)->name) != NULL); + expected_callback_cat = NULL; + break; + + case UNREG_LAST: + /* must be registered to unregister */ + test_assert(event_category_find_registered((cat)->name) != NULL); + expected_callback_cat = cat; + break; + + case UNREG_NOP: + /* must not be registered for no-op */ + /* event_category_find_registered(cat->name) should return + NULL, but since we don't actually unregister this lookup + would fail. Therefore, we skip it. */ + expected_callback_cat = NULL; + break; + } + + /* Note: We don't actually have a way to unregister categories. We + keep the above checks and the calls to this function as a form of + documentation of how unregistering should work. */ +} + +static void test_event_category_1ptr_null(void) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-1ptr-null" + static struct event_category cat = { .name = CAT_NAME_0 }; + + test_begin("event category rereg: same ptr, NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + register_cat(&cat, &cat); + register_cat(&cat, NULL); + check_cat_registered(CAT_NAME_0, TRUE); + + unregister_cat(&cat, UNREG_LAST); + unregister_cat(&cat, UNREG_NOP); + + test_end(); +#undef CAT_NAME_0 +} + +static void test_event_category_1ptr_nonnull(void) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-1ptr-nonnull-0" +#define CAT_NAME_1 CAT_NAME_PREFIX "-1ptr-nonnull-1" + static struct event_category cat = { .name = CAT_NAME_0 }; + static struct event_category cat_with_parent = { .name = CAT_NAME_1, .parent = &cat }; + + test_begin("event category rereg: same ptr, non-NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + check_cat_registered(CAT_NAME_1, FALSE); + register_cat(&cat, &cat); + register_cat(&cat_with_parent, &cat_with_parent); + register_cat(&cat_with_parent, NULL); + check_cat_registered(CAT_NAME_0, TRUE); + check_cat_registered(CAT_NAME_1, TRUE); + + unregister_cat(&cat_with_parent, UNREG_LAST); + unregister_cat(&cat_with_parent, UNREG_NOP); + /* NOTE: we must unreg children before parent cats */ + unregister_cat(&cat, UNREG_LAST); + unregister_cat(&cat, UNREG_NOP); + + test_end(); +#undef CAT_NAME_0 +#undef CAT_NAME_1 +} + +static void test_event_category_2ptr_null(void) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-null" + static struct event_category cat0 = { .name = CAT_NAME_0 }; + static struct event_category cat1 = { .name = CAT_NAME_0 }; + + test_begin("event category rereg: different ptr, NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + register_cat(&cat0, &cat0); + register_cat(&cat1, NULL); + check_cat_registered(CAT_NAME_0, TRUE); + + unregister_cat(&cat0, UNREG_NOT_LAST); + unregister_cat(&cat1, UNREG_LAST); + unregister_cat(&cat0, UNREG_NOP); + unregister_cat(&cat1, UNREG_NOP); + + test_end(); +#undef CAT_NAME_0 +} + +static void test_event_category_2ptr_nonnull_same(void) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-same-0" +#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-same-1" + static struct event_category cat = { .name = CAT_NAME_0 }; + static struct event_category cat_with_parent0 = { .name = CAT_NAME_1, .parent = &cat }; + static struct event_category cat_with_parent1 = { .name = CAT_NAME_1, .parent = &cat }; + + test_begin("event category rereg: different ptr, same non-NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + check_cat_registered(CAT_NAME_1, FALSE); + register_cat(&cat, &cat); + register_cat(&cat_with_parent0, &cat_with_parent0); + register_cat(&cat_with_parent1, NULL); + check_cat_registered(CAT_NAME_0, TRUE); + check_cat_registered(CAT_NAME_1, TRUE); + + unregister_cat(&cat_with_parent0, UNREG_NOT_LAST); + unregister_cat(&cat_with_parent1, UNREG_LAST); + unregister_cat(&cat_with_parent0, UNREG_NOP); + unregister_cat(&cat_with_parent1, UNREG_NOP); + /* NOTE: we must unreg children before parent cats */ + unregister_cat(&cat, UNREG_LAST); + unregister_cat(&cat, UNREG_NOP); + + test_end(); +#undef CAT_NAME_0 +#undef CAT_NAME_1 +} + +static void test_event_category_2ptr_nonnull_similar(void) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-similar-0" +#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-similar-1" + static struct event_category cat0 = { .name = CAT_NAME_0 }; + static struct event_category cat1 = { .name = CAT_NAME_0 }; + static struct event_category cat_with_parent0 = { .name = CAT_NAME_1, .parent = &cat0 }; + static struct event_category cat_with_parent1 = { .name = CAT_NAME_1, .parent = &cat1 }; + + test_begin("event category rereg: different ptr, similar non-NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + check_cat_registered(CAT_NAME_1, FALSE); + register_cat(&cat0, &cat0); + register_cat(&cat1, NULL); + register_cat(&cat_with_parent0, &cat_with_parent0); + register_cat(&cat_with_parent1, NULL); + check_cat_registered(CAT_NAME_0, TRUE); + check_cat_registered(CAT_NAME_1, TRUE); + + unregister_cat(&cat_with_parent0, UNREG_NOT_LAST); + unregister_cat(&cat_with_parent1, UNREG_LAST); + unregister_cat(&cat_with_parent0, UNREG_NOP); + unregister_cat(&cat_with_parent1, UNREG_NOP); + /* NOTE: we must unreg children before parent cats */ + unregister_cat(&cat0, UNREG_NOT_LAST); + unregister_cat(&cat1, UNREG_LAST); + unregister_cat(&cat0, UNREG_NOP); + unregister_cat(&cat1, UNREG_NOP); + + test_end(); +#undef CAT_NAME_0 +#undef CAT_NAME_1 +} + +void test_event_category_register(void) +{ + event_category_register_callback(check_category); + + /* + * registering/unregistering the same exact category struct (i.e., + * the pointer is the same) is a no-op after the first call + */ + test_event_category_1ptr_null(); + test_event_category_1ptr_nonnull(); + + /* + * registering/unregistering two different category structs (i.e., + * the pointers are different) is a almost a no-op + */ + test_event_category_2ptr_null(); + test_event_category_2ptr_nonnull_same(); + test_event_category_2ptr_nonnull_similar(); + + event_category_unregister_callback(check_category); +} + +enum fatal_test_state fatal_event_category_register(unsigned int stage) +{ +#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-different-0" +#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-different-1" +#define CAT_NAME_2 CAT_NAME_PREFIX "-2ptr-nonnull-different-2" + static struct event_category cat_no_parent0 = { .name = CAT_NAME_0 }; + static struct event_category cat_parent0 = { .name = CAT_NAME_1, .parent = &cat_no_parent0 }; + static struct event_category cat_other = { .name = CAT_NAME_2 }; + static struct event_category cat_other_parent = { .name = CAT_NAME_1, .parent = &cat_other }; + + /* we have only one fatal stage at this point */ + switch (stage) { + case 0: + event_category_register_callback(check_category); + + test_begin("event category rereg: different ptr, different non-NULL parent"); + + check_cat_registered(CAT_NAME_0, FALSE); + check_cat_registered(CAT_NAME_1, FALSE); + check_cat_registered(CAT_NAME_2, FALSE); + register_cat(&cat_no_parent0, &cat_no_parent0); + register_cat(&cat_other, &cat_other); + register_cat(&cat_parent0, &cat_parent0); + + test_expect_fatal_string("event category parent mismatch detected"); + register_cat(&cat_other_parent, NULL); /* expected panic */ + + return FATAL_TEST_FAILURE; + case 1: + event_unref(&dummy_event); + + unregister_cat(&cat_parent0, UNREG_LAST); + unregister_cat(&cat_parent0, UNREG_NOP); + unregister_cat(&cat_other, UNREG_LAST); + unregister_cat(&cat_other, UNREG_NOP); + /* NOTE: we must unreg children before parent cats */ + unregister_cat(&cat_no_parent0, UNREG_LAST); + unregister_cat(&cat_no_parent0, UNREG_NOP); + + test_end(); + + event_category_unregister_callback(check_category); + + return FATAL_TEST_FINISHED; + + default: + return FATAL_TEST_ABORT; + } +#undef CAT_NAME_0 +#undef CAT_NAME_1 +#undef CAT_NAME_2 +} |