]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Test category re-registration thoroughly
authorJosef 'Jeff' Sipek <jeff.sipek@open-xchange.com>
Mon, 4 Nov 2019 20:37:17 +0000 (15:37 -0500)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 22 Nov 2019 10:44:16 +0000 (12:44 +0200)
src/lib/Makefile.am
src/lib/test-event-category-register.c [new file with mode: 0644]
src/lib/test-lib.inc

index e737f50e4b7fef71e5ee4d284222cf46dcea6f92..45f1863dd58291a83a8995946507d0f46b1a5539 100644 (file)
@@ -347,6 +347,7 @@ test_lib_SOURCES = \
        test-connection.c \
        test-crc32.c \
        test-data-stack.c \
+       test-event-category-register.c \
        test-event-filter.c \
        test-event-flatten.c \
        test-event-log.c \
diff --git a/src/lib/test-event-category-register.c b/src/lib/test-event-category-register.c
new file mode 100644 (file)
index 0000000..50cc038
--- /dev/null
@@ -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
+}
index 0d2895fc293e0a85825cd9473c424648396af2a5..e83dda4d2eb5f5812f76ac2c120e5f05b2f0f112 100644 (file)
@@ -16,6 +16,8 @@ TEST(test_connection)
 TEST(test_crc32)
 TEST(test_data_stack)
 FATAL(fatal_data_stack)
+TEST(test_event_category_register)
+FATAL(fatal_event_category_register)
 TEST(test_event_filter)
 TEST(test_event_flatten)
 TEST(test_event_log)