summaryrefslogtreecommitdiffstats
path: root/src/lib/test-event-category-register.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/test-event-category-register.c')
-rw-r--r--src/lib/test-event-category-register.c320
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
+}