Merged revisions 321871 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Fri, 3 Jun 2011 21:02:32 +0000 (21:02 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 3 Jun 2011 21:02:32 +0000 (21:02 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r321871 | rmudgett | 2011-06-03 15:58:13 -0500 (Fri, 03 Jun 2011) | 27 lines

  Event subscription fixes.

  Must commit the subscription fixes together with the integration
  subscription tests.  The subscription fixes cause an erroneously passing
  test to fail.  The new subscription tests detect errors without the
  subscription fixes.

  * Added missing event_names[] table entry.

  * Reworked ast_event_check_subscriber()/match_sub_ie_val_to_event() to
  correctly detect if a subscriber exists for the proposed event.

  * Made match_ie_val() and match_sub_ie_val_to_event() check the buffer
  length for RAW payload types.

  * Fixed error handling memory leak in ast_event_sub_activate(),
  ast_event_unsubscribe(), and ast_event_queue().

  * Made ast_event_new() and ast_event_check_subscriber() better protect
  themselves from an invalid payload type.

  * Added container lock protection between removing old cache events and
  adding the new cached event in
  ast_event_queue_and_cache()/event_update_cache().

  * Added new event subscription tests.
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@321872 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/event.c
tests/test_event.c

index a50f611..246821e 100644 (file)
@@ -194,6 +194,7 @@ static const char * const cached_event_types[] = { "MWI", "DeviceState", "Device
  * \brief Event Names
  */
 static const char * const event_names[AST_EVENT_TOTAL] = {
+       [AST_EVENT_ALL]                 = "All",
        [AST_EVENT_CUSTOM]              = "Custom",
        [AST_EVENT_MWI]                 = "MWI",
        [AST_EVENT_SUB]                 = "Subscription",
@@ -359,53 +360,72 @@ static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
        ast_free(ie_val);
 }
 
+/*! \brief Subscription event check list. */
+struct ast_ev_check_list {
+       AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
+};
+
 /*!
  * \internal
- * \brief Check if an ie_val matches a subscription
+ * \brief Check if a subscription ie_val matches an event.
  *
- * \param sub subscription to check against
- * \param ie_val IE value to check
+ * \param sub_ie_val Subscripton IE value to check
+ * \param check_ie_vals event list to check against
  *
  * \retval 0 not matched
  * \retval non-zero matched
  */
-static int match_ie_val_to_sub(const struct ast_event_sub *sub, const struct ast_event_ie_val *ie_val)
+static int match_sub_ie_val_to_event(const struct ast_event_ie_val *sub_ie_val, const struct ast_ev_check_list *check_ie_vals)
 {
-       const struct ast_event_ie_val *sub_ie_val;
-       int res = 1;
+       const struct ast_event_ie_val *event_ie_val;
+       int res = 0;
 
-       AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
-               if (sub_ie_val->ie_type == ie_val->ie_type) {
+       AST_LIST_TRAVERSE(&check_ie_vals->ie_vals, event_ie_val, entry) {
+               if (event_ie_val->ie_type == sub_ie_val->ie_type) {
                        break;
                }
        }
+       if (!event_ie_val) {
+               /* The did not find the event ie the subscriber cares about. */
+               return 0;
+       }
 
-       if (!sub_ie_val) {
-               /* This subscriber doesn't care about this IE, so consider
-                * it matched. */
-               return 1;
+       if (sub_ie_val->ie_pltype != event_ie_val->ie_pltype) {
+               if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+                       /* The subscription only cares that this ie exists. */
+                       return 1;
+               }
+               /* Payload types do not match. */
+               return 0;
        }
 
-       switch (ie_val->ie_pltype) {
+       switch (sub_ie_val->ie_pltype) {
        case AST_EVENT_IE_PLTYPE_UINT:
-               res = (ie_val->payload.uint != sub_ie_val->payload.uint);
+               res = (sub_ie_val->payload.uint == event_ie_val->payload.uint);
                break;
        case AST_EVENT_IE_PLTYPE_BITFLAGS:
                /*
                 * If the subscriber has requested *any* of the bitflags we are providing,
                 * then it's a match.
                 */
-               res = !(ie_val->payload.uint & sub_ie_val->payload.uint);
+               res = (sub_ie_val->payload.uint & event_ie_val->payload.uint);
                break;
        case AST_EVENT_IE_PLTYPE_STR:
-               res = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
+               res = !strcmp(sub_ie_val->payload.str, event_ie_val->payload.str);
                break;
        case AST_EVENT_IE_PLTYPE_RAW:
-               res = memcmp(ie_val->payload.raw,
-                               sub_ie_val->payload.raw, ie_val->raw_datalen);
+               res = (sub_ie_val->raw_datalen == event_ie_val->raw_datalen
+                       && !memcmp(sub_ie_val->payload.raw, event_ie_val->payload.raw,
+                               sub_ie_val->raw_datalen));
                break;
        case AST_EVENT_IE_PLTYPE_EXISTS:
+               /* Should never get here since check_ie_vals cannot have this type. */
+               break;
        case AST_EVENT_IE_PLTYPE_UNKNOWN:
+               /*
+                * Should never be in a subscription event ie val list and
+                * check_ie_vals cannot have this type either.
+                */
                break;
        }
 
@@ -419,7 +439,9 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
        enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
        struct ast_event_ie_val *ie_val;
        struct ast_event_sub *sub;
-       AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
+       struct ast_ev_check_list check_ie_vals = {
+               .ie_vals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
+       };
        const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
        int i;
 
@@ -434,37 +456,45 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
                ie_type = va_arg(ap, enum ast_event_ie_type))
        {
                struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
-               int insert = 1;
+               int insert = 0;
+
                memset(ie_value, 0, sizeof(*ie_value));
                ie_value->ie_type = ie_type;
                ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
                switch (ie_value->ie_pltype) {
                case AST_EVENT_IE_PLTYPE_UINT:
                        ie_value->payload.uint = va_arg(ap, uint32_t);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_BITFLAGS:
                        ie_value->payload.uint = va_arg(ap, uint32_t);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_STR:
                        ie_value->payload.str = va_arg(ap, const char *);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_RAW:
                {
                        void *data = va_arg(ap, void *);
                        size_t datalen = va_arg(ap, size_t);
+
                        ie_value->payload.raw = alloca(datalen);
                        memcpy(ie_value->payload.raw, data, datalen);
                        ie_value->raw_datalen = datalen;
+                       insert = 1;
                        break;
                }
                case AST_EVENT_IE_PLTYPE_UNKNOWN:
-                       insert = 0;
                case AST_EVENT_IE_PLTYPE_EXISTS:
+                       /* Unsupported payload type. */
                        break;
                }
 
                if (insert) {
-                       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
+                       AST_LIST_INSERT_TAIL(&check_ie_vals.ie_vals, ie_value, entry);
+               } else {
+                       ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
                }
        }
        va_end(ap);
@@ -472,14 +502,14 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
        for (i = 0; i < ARRAY_LEN(event_types); i++) {
                AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
                AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
-                       AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
-                               if (match_ie_val_to_sub(sub, ie_val)) {
+                       AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+                               if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) {
+                                       /* The current subscription ie did not match an event ie. */
                                        break;
                                }
                        }
-
                        if (!ie_val) {
-                               /* Everything matched. */
+                               /* Everything matched.  A subscriber is looking for this event. */
                                break;
                        }
                }
@@ -550,7 +580,9 @@ static int match_ie_val(const struct ast_event *event,
                const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
                uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
 
-               return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
+               return (buf
+                       && ie_payload_len == ast_event_get_ie_raw_payload_len(event, ie_val->ie_type)
+                       && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
        }
 
        case AST_EVENT_IE_PLTYPE_EXISTS:
@@ -603,7 +635,6 @@ static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
                AST_EVENT_IE_EVENTTYPE,   AST_EVENT_IE_PLTYPE_UINT, sub->type,
                AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
                AST_EVENT_IE_END);
-
        if (!event)
                return NULL;
 
@@ -662,7 +693,6 @@ void ast_event_report_subs(const struct ast_event_sub *event_sub)
                }
 
                event = gen_sub_event(sub);
-
                if (!event) {
                        continue;
                }
@@ -826,9 +856,8 @@ int ast_event_sub_activate(struct ast_event_sub *sub)
                struct ast_event *event;
 
                event = gen_sub_event(sub);
-
-               if (event) {
-                       ast_event_queue(event);
+               if (event && ast_event_queue(event)) {
+                       ast_event_destroy(event);
                }
        }
 
@@ -934,9 +963,8 @@ struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
                        AST_EVENT_IE_EVENTTYPE,   AST_EVENT_IE_PLTYPE_UINT, sub->type,
                        AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
                        AST_EVENT_IE_END);
-
-               if (event) {
-                       ast_event_queue(event);
+               if (event && ast_event_queue(event)) {
+                       ast_event_destroy(event);
                }
        }
 
@@ -1145,19 +1173,23 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                ie_type = va_arg(ap, enum ast_event_ie_type))
        {
                struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
-               int insert = 1;
+               int insert = 0;
+
                memset(ie_value, 0, sizeof(*ie_value));
                ie_value->ie_type = ie_type;
                ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
                switch (ie_value->ie_pltype) {
                case AST_EVENT_IE_PLTYPE_UINT:
                        ie_value->payload.uint = va_arg(ap, uint32_t);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_BITFLAGS:
                        ie_value->payload.uint = va_arg(ap, uint32_t);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_STR:
                        ie_value->payload.str = va_arg(ap, const char *);
+                       insert = 1;
                        break;
                case AST_EVENT_IE_PLTYPE_RAW:
                {
@@ -1166,11 +1198,10 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                        ie_value->payload.raw = alloca(datalen);
                        memcpy(ie_value->payload.raw, data, datalen);
                        ie_value->raw_datalen = datalen;
+                       insert = 1;
                        break;
                }
                case AST_EVENT_IE_PLTYPE_UNKNOWN:
-                       insert = 0;
-                       break;
                case AST_EVENT_IE_PLTYPE_EXISTS:
                        break;
                }
@@ -1178,6 +1209,8 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                if (insert) {
                        AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
                        has_ie = 1;
+               } else {
+                       ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
                }
        }
        va_end(ap);
@@ -1205,11 +1238,7 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                                        ie_val->payload.raw, ie_val->raw_datalen);
                        break;
                case AST_EVENT_IE_PLTYPE_EXISTS:
-                       ast_log(LOG_WARNING, "PLTYPE_EXISTS unsupported in event_new\n");
-                       break;
                case AST_EVENT_IE_PLTYPE_UNKNOWN:
-                       ast_log(LOG_WARNING, "PLTYPE_UNKNOWN passed as an IE type "
-                                       "for a new event\n");
                        break;
                }
 
@@ -1342,52 +1371,62 @@ static struct ast_event_ref *alloc_event_ref(void)
        return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
 }
 
-/*! \brief Duplicate an event and add it to the cache
- * \note This assumes this index in to the cache is locked */
-static int ast_event_dup_and_cache(const struct ast_event *event)
+/*!
+ * \internal
+ * \brief Update the given event cache with the new event.
+ * \since 1.8
+ *
+ * \param cache Event cache container to update.
+ * \param event New event to put in the cache.
+ *
+ * \return Nothing
+ */
+static void event_update_cache(struct ao2_container *cache, struct ast_event *event)
 {
+       struct ast_event_ref tmp_event_ref = {
+               .event = event,
+       };
        struct ast_event *dup_event;
        struct ast_event_ref *event_ref;
 
-       if (!(dup_event = ast_event_dup(event))) {
-               return -1;
-       }
-
-       if (!(event_ref = alloc_event_ref())) {
-               ast_event_destroy(dup_event);
-               return -1;
+       /* Hold the cache container lock while it is updated. */
+       ao2_lock(cache);
+
+       /* Remove matches from the cache. */
+       ao2_callback(cache, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
+               ast_event_cmp, &tmp_event_ref);
+
+       /* Save a copy of the event in the cache. */
+       dup_event = ast_event_dup(event);
+       if (dup_event) {
+               event_ref = alloc_event_ref();
+               if (event_ref) {
+                       event_ref->event = dup_event;
+                       ao2_link(cache, event_ref);
+                       ao2_ref(event_ref, -1);
+               } else {
+                       ast_event_destroy(dup_event);
+               }
        }
 
-       event_ref->event = dup_event;
-
-       ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
-
-       ao2_ref(event_ref, -1);
-
-       return 0;
+       ao2_unlock(cache);
 }
 
 int ast_event_queue_and_cache(struct ast_event *event)
 {
        struct ao2_container *container;
-       struct ast_event_ref tmp_event_ref = {
-               .event = event,
-       };
-       int res = -1;
 
-       if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
+       container = ast_event_cache[ast_event_get_type(event)].container;
+       if (!container) {
                ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
-               goto queue_event;
+       } else {
+               event_update_cache(container, event);
        }
 
-       /* Remove matches from the cache */
-       ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
-                       ast_event_cmp, &tmp_event_ref);
-
-       res = ast_event_dup_and_cache(event);
-
-queue_event:
-       return ast_event_queue(event) ? -1 : res;
+       if (ast_event_queue(event)) {
+               ast_event_destroy(event);
+       }
+       return 0;
 }
 
 static int handle_event(void *data)
@@ -1404,12 +1443,15 @@ static int handle_event(void *data)
                AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
                AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
                        struct ast_event_ie_val *ie_val;
+
                        AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
                                if (!match_ie_val(event_ref->event, ie_val, NULL)) {
+                                       /* The current subscription ie did not match an event ie. */
                                        break;
                                }
                        }
                        if (ie_val) {
+                               /* The event did not match this subscription. */
                                continue;
                        }
                        sub->cb(event_ref->event, sub->userdata);
@@ -1426,6 +1468,7 @@ int ast_event_queue(struct ast_event *event)
 {
        struct ast_event_ref *event_ref;
        uint16_t host_event_type;
+       int res;
 
        host_event_type = ntohs(event->type);
 
@@ -1449,7 +1492,12 @@ int ast_event_queue(struct ast_event *event)
 
        event_ref->event = event;
 
-       return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
+       res = ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
+       if (res) {
+               event_ref->event = NULL;
+               ao2_ref(event_ref, -1);
+       }
+       return res;
 }
 
 static int ast_event_hash_mwi(const void *obj, const int flags)
index 4331d74..5f0c100 100644 (file)
@@ -240,6 +240,53 @@ static void event_sub_cb(const struct ast_event *event, void *d)
        data->count++;
 }
 
+enum test_subs_class_type {
+       TEST_SUBS_ALL_STR,
+       TEST_SUBS_CUSTOM_STR,
+       TEST_SUBS_CUSTOM_RAW,
+       TEST_SUBS_CUSTOM_UINT,
+       TEST_SUBS_CUSTOM_BITFLAGS,
+       TEST_SUBS_CUSTOM_EXISTS,
+       TEST_SUBS_CUSTOM_DYNAMIC,
+       TEST_SUBS_CUSTOM_ANY,
+
+       /* Must be last. */
+       TEST_SUBS_TOTAL,
+};
+
+/*!
+ * \internal
+ * \brief Convert enum test_subs_class_type to string.
+ *
+ * \param val Enum value to convert to string.
+ *
+ * \return String equivalent of enum value.
+ */
+static const char *test_subs_class_type_str(enum test_subs_class_type val)
+{
+       switch (val) {
+       case TEST_SUBS_ALL_STR:
+               return "TEST_SUBS_ALL_STR";
+       case TEST_SUBS_CUSTOM_STR:
+               return "TEST_SUBS_CUSTOM_STR";
+       case TEST_SUBS_CUSTOM_RAW:
+               return "TEST_SUBS_CUSTOM_RAW";
+       case TEST_SUBS_CUSTOM_UINT:
+               return "TEST_SUBS_CUSTOM_UINT";
+       case TEST_SUBS_CUSTOM_BITFLAGS:
+               return "TEST_SUBS_CUSTOM_BITFLAGS";
+       case TEST_SUBS_CUSTOM_EXISTS:
+               return "TEST_SUBS_CUSTOM_EXISTS";
+       case TEST_SUBS_CUSTOM_DYNAMIC:
+               return "TEST_SUBS_CUSTOM_DYNAMIC";
+       case TEST_SUBS_CUSTOM_ANY:
+               return "TEST_SUBS_CUSTOM_ANY";
+       case TEST_SUBS_TOTAL:
+               break;
+       }
+       return "Unknown";
+}
+
 /*!
  * \internal
  * \brief Test event subscriptions
@@ -257,16 +304,31 @@ AST_TEST_DEFINE(event_sub_test)
                struct ast_event_sub *sub;
                struct event_sub_data data;
                const unsigned int expected_count;
-       } test_subs[] = {
-               [0] = {
-                       .expected_count = 3,
+       } test_subs[TEST_SUBS_TOTAL] = {
+               [TEST_SUBS_ALL_STR] = {
+                       .expected_count = 2,
                },
-               [1] = {
+               [TEST_SUBS_CUSTOM_STR] = {
+                       .expected_count = 2,
+               },
+               [TEST_SUBS_CUSTOM_RAW] = {
+                       .expected_count = 1,
+               },
+               [TEST_SUBS_CUSTOM_UINT] = {
                        .expected_count = 1,
                },
-               [2] = {
+               [TEST_SUBS_CUSTOM_BITFLAGS] = {
+                       .expected_count = 4,
+               },
+               [TEST_SUBS_CUSTOM_EXISTS] = {
                        .expected_count = 2,
                },
+               [TEST_SUBS_CUSTOM_DYNAMIC] = {
+                       .expected_count = 1,
+               },
+               [TEST_SUBS_CUSTOM_ANY] = {
+                       .expected_count = 6,
+               },
        };
 
        switch (cmd) {
@@ -283,115 +345,230 @@ AST_TEST_DEFINE(event_sub_test)
        }
 
        /*
-        * Subscription #1:
+        * Subscription TEST_SUBS_ALL_STR:
         *  - allocate normally
-        *  - subscribe to all CUSTOM events
-        *
-        * Subscription #2:
-        *  - allocate dynamically
-        *  - subscribe to all CUSTOM events
-        *  - add payload checks
-        *
-        * Subscription #3:
+        *  - subscribe to ALL events with a DEVICE STR IE check
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_ALL_STR subscription\n");
+       test_subs[TEST_SUBS_ALL_STR].sub = ast_event_subscribe(AST_EVENT_ALL, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_ALL_STR), &test_subs[TEST_SUBS_ALL_STR].data,
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_ALL_STR].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_ALL_STR subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_ALL_STR].sub),
+               test_subs_class_type_str(TEST_SUBS_ALL_STR))) {
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_ALL_STR subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       /*
+        * Subscription TEST_SUBS_CUSTOM_STR:
         *  - allocate normally
-        *  - subscribe to all events with an IE check
+        *  - subscribe to CUSTOM events with a DEVICE STR IE check
         */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_STR subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_STR].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_STR), &test_subs[TEST_SUBS_CUSTOM_STR].data,
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_STR].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_STR subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
 
-       test_subs[0].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb, "test_sub", &test_subs[0].data,
-                       AST_EVENT_IE_END);
-       if (!test_subs[0].sub) {
-               ast_test_status_update(test, "Failed to create test_subs[0].sub\n");
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_STR].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_STR))) {
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_STR subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (strcmp(ast_event_subscriber_get_description(test_subs[0].sub), "test_sub")) {
+       /*
+        * Subscription TEST_SUBS_CUSTOM_RAW:
+        *  - allocate normally
+        *  - subscribe to CUSTOM events with a MAILBOX RAW IE check
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_RAW subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_RAW].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_RAW), &test_subs[TEST_SUBS_CUSTOM_RAW].data,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_RAW].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_RAW subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_RAW].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_RAW))) {
                ast_test_status_update(test,
-                               "Unexpected subscription description on test_subs[0].sub\n");
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_RAW subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       test_subs[1].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM, event_sub_cb, &test_subs[1].data);
-       if (!test_subs[1].sub) {
-               ast_test_status_update(test, "Failed to create test_subs[1].sub\n");
+       /*
+        * Subscription TEST_SUBS_CUSTOM_UINT:
+        *  - allocate normally
+        *  - subscribe to CUSTOM events with a NEWMSGS UINT IE check
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_UINT subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_UINT].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_UINT), &test_subs[TEST_SUBS_CUSTOM_UINT].data,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_UINT].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_UINT subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       /* For the sake of exercising destruction before activation */
-       ast_event_sub_destroy(test_subs[1].sub);
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_UINT].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_UINT))) {
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_UINT subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
 
-       test_subs[1].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM, event_sub_cb, &test_subs[1].data);
-       if (!test_subs[1].sub) {
-               ast_test_status_update(test, "Failed to create test_subs[1].sub\n");
+       /*
+        * Subscription TEST_SUBS_CUSTOM_BITFLAGS:
+        *  - allocate normally
+        *  - subscribe to CUSTOM events with a NEWMSGS BITFLAGS IE check
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_BITFLAGS), &test_subs[TEST_SUBS_CUSTOM_BITFLAGS].data,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 0x06,
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (strcmp(ast_event_subscriber_get_description(test_subs[1].sub), "")) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_BITFLAGS].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_BITFLAGS))) {
                ast_test_status_update(test,
-                               "Unexpected subscription description on test_subs[1].sub\n");
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_BITFLAGS subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (ast_event_sub_append_ie_uint(test_subs[1].sub, AST_EVENT_IE_NEWMSGS, 3)) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to append uint IE to test_subs[1].sub\n");
+       /*
+        * Subscription TEST_SUBS_CUSTOM_EXISTS:
+        *  - allocate normally
+        *  - subscribe to CUSTOM events with a NEWMSGS UINT and OLDMSGS EXISTS IE check
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_EXISTS subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_EXISTS].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_EXISTS), &test_subs[TEST_SUBS_CUSTOM_EXISTS].data,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_EXISTS].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_EXISTS subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (ast_event_sub_append_ie_bitflags(test_subs[1].sub, AST_EVENT_IE_NEWMSGS, 1)) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to append bitflags IE to test_subs[1].sub\n");
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_EXISTS].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_EXISTS))) {
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_EXISTS subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (ast_event_sub_append_ie_str(test_subs[1].sub, AST_EVENT_IE_DEVICE, "FOO/bar")) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to append str IE to test_subs[1].sub\n");
+       /* For the sake of exercising destruction before activation */
+       test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM,
+               event_sub_cb, &test_subs[TEST_SUBS_CUSTOM_DYNAMIC].data);
+       if (!test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
+       ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
 
-       if (ast_event_sub_append_ie_raw(test_subs[1].sub, AST_EVENT_IE_MAILBOX, "800 km",
-                       strlen("800 km"))) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to append raw IE to test_subs[1].sub\n");
+       /*
+        * Subscription TEST_SUBS_CUSTOM_DYNAMIC:
+        *  - allocate dynamically
+        *  - subscribe to all CUSTOM events
+        *  - add IE checks for all types
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = ast_event_subscribe_new(AST_EVENT_CUSTOM,
+               event_sub_cb, &test_subs[TEST_SUBS_CUSTOM_DYNAMIC].data);
+       if (!test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (ast_event_sub_append_ie_exists(test_subs[1].sub, AST_EVENT_IE_DEVICE)) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to append exists IE to test_subs[1].sub\n");
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub),
+               "")) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       if (ast_event_sub_activate(test_subs[1].sub)) {
-               ast_event_sub_destroy(test_subs[1].sub);
-               test_subs[1].sub = NULL;
-               ast_test_status_update(test, "Failed to activate test_subs[1].sub\n");
+       if (ast_event_sub_append_ie_uint(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_NEWMSGS, 4)) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to append UINT IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
-       test_subs[2].sub = ast_event_subscribe(AST_EVENT_ALL, event_sub_cb, "test_sub", &test_subs[2].data,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
-                       AST_EVENT_IE_END);
-       if (!test_subs[2].sub) {
-               ast_test_status_update(test, "Failed to create test_subs[2].sub\n");
+       if (ast_event_sub_append_ie_bitflags(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_OLDMSGS, 1)) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to append BITFLAGS IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (ast_event_sub_append_ie_str(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_DEVICE, "FOO/bar")) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to append STR IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (ast_event_sub_append_ie_raw(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_MAILBOX, "800 km",
+                       strlen("800 km"))) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to append RAW IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (ast_event_sub_append_ie_exists(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub, AST_EVENT_IE_STATE)) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to append EXISTS IE to TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (ast_event_sub_activate(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub)) {
+               ast_event_sub_destroy(test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub);
+               test_subs[TEST_SUBS_CUSTOM_DYNAMIC].sub = NULL;
+               ast_test_status_update(test, "Failed to activate TEST_SUBS_CUSTOM_DYNAMIC subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
@@ -399,42 +576,219 @@ AST_TEST_DEFINE(event_sub_test)
        /*
         * Exercise the API call to check for existing subscriptions.
         */
+       ast_test_status_update(test, "Checking for subscribers to events\n");
 
+       /* Check STR matching. */
        sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
-                       AST_EVENT_IE_END);
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+               AST_EVENT_IE_END);
        if (sub_res != AST_EVENT_SUB_EXISTS) {
-               ast_test_status_update(test, "subscription did not exist\n");
+               ast_test_status_update(test, "Str FOO/bar subscription did not exist\n");
                res = AST_TEST_FAIL;
-               goto return_cleanup;
        }
 
        sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "BOOBS",
-                       AST_EVENT_IE_END);
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Money",
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_NONE) {
+               ast_test_status_update(test, "Str Money subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       /* Check RAW matching. */
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_EXISTS) {
+               ast_test_status_update(test, "Raw FOO/bar subscription did not exist\n");
+               res = AST_TEST_FAIL;
+       }
+
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar") - 1,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_NONE) {
+               ast_test_status_update(test, "Raw FOO/bar-1 subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "Monkeys", sizeof("Monkeys"),
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_NONE) {
+               ast_test_status_update(test, "Raw Monkeys subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       /* Check UINT matching. */
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_EXISTS) {
+               ast_test_status_update(test, "UINT=5 subscription did not exist\n");
+               res = AST_TEST_FAIL;
+       }
+
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 1,
+               AST_EVENT_IE_END);
        if (sub_res != AST_EVENT_SUB_NONE) {
-               ast_test_status_update(test, "Someone subscribed to updates on boobs, lol? (%d)\n", sub_res);
+               ast_test_status_update(test, "UINT=1 subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       /* Check BITFLAGS matching. */
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 2,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_EXISTS) {
+               ast_test_status_update(test, "BITFLAGS=2 subscription did not exist\n");
+               res = AST_TEST_FAIL;
+       }
+
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_BITFLAGS, 8,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_NONE) {
+               ast_test_status_update(test, "BITFLAGS=8 subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       /* Check EXISTS matching. */
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 100,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_EXISTS) {
+               ast_test_status_update(test, "EXISTS subscription did not exist\n");
+               res = AST_TEST_FAIL;
+       }
+
+       sub_res = ast_event_check_subscriber(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_END);
+       if (sub_res != AST_EVENT_SUB_NONE) {
+               ast_test_status_update(test, "EXISTS subscription should not exist! (%d)\n",
+                       sub_res);
+               res = AST_TEST_FAIL;
+       }
+
+       /*
+        * Subscription TEST_SUBS_CUSTOM_ANY:
+        *  - allocate normally
+        *  - subscribe to all CUSTOM events
+        */
+       ast_test_status_update(test, "Adding TEST_SUBS_CUSTOM_ANY subscription\n");
+       test_subs[TEST_SUBS_CUSTOM_ANY].sub = ast_event_subscribe(AST_EVENT_CUSTOM, event_sub_cb,
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_ANY), &test_subs[TEST_SUBS_CUSTOM_ANY].data,
+               AST_EVENT_IE_END);
+       if (!test_subs[TEST_SUBS_CUSTOM_ANY].sub) {
+               ast_test_status_update(test, "Failed to create TEST_SUBS_CUSTOM_ANY subscription\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       if (strcmp(ast_event_subscriber_get_description(test_subs[TEST_SUBS_CUSTOM_ANY].sub),
+               test_subs_class_type_str(TEST_SUBS_CUSTOM_ANY))) {
+               ast_test_status_update(test,
+                       "Unexpected subscription description on TEST_SUBS_CUSTOM_ANY subscription\n");
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
 
        /*
         * Fire off some events and track what was received in the callback
+        */
+       ast_test_status_update(test, "Posting test events\n");
+
+       /*
+        * Event to check STR matching.
         *
-        * event #1:
-        *  - simple custom event (will match sub 1 and 3)
+        * Matching subscriptions:
+        * TEST_SUBS_ALL_STR
+        * TEST_SUBS_CUSTOM_STR
+        * TEST_SUBS_CUSTOM_ANY
+        */
+       event = ast_event_new(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar") - 1,
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+               AST_EVENT_IE_END);
+       if (!event) {
+               ast_test_status_update(test, "Failed to create event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+       if (ast_event_queue(event)) {
+               ast_event_destroy(event);
+               event = NULL;
+               ast_test_status_update(test, "Failed to queue event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       /*
+        * Event to check RAW matching.
         *
-        * event #2:
-        *  - custom event with payloads that satisfy every payload check
-        *    for sub #2 (will match sub 1, 2, and 3)
+        * Matching subscriptions:
+        * TEST_SUBS_CUSTOM_RAW
+        * TEST_SUBS_CUSTOM_ANY
+        */
+       event = ast_event_new(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Misery",
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "FOO/bar", sizeof("FOO/bar"),
+               AST_EVENT_IE_END);
+       if (!event) {
+               ast_test_status_update(test, "Failed to create event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+       if (ast_event_queue(event)) {
+               ast_event_destroy(event);
+               event = NULL;
+               ast_test_status_update(test, "Failed to queue event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+
+       /*
+        * Event to check UINT matching.
         *
-        * event #3:
-        *  - custom event that should only match sub #1
+        * Matching subscriptions:
+        * TEST_SUBS_CUSTOM_UINT
+        * TEST_SUBS_CUSTOM_BITFLAGS
+        * TEST_SUBS_CUSTOM_ANY
         */
+       event = ast_event_new(AST_EVENT_CUSTOM,
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+               AST_EVENT_IE_END);
+       if (!event) {
+               ast_test_status_update(test, "Failed to create event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
+       if (ast_event_queue(event)) {
+               ast_event_destroy(event);
+               event = NULL;
+               ast_test_status_update(test, "Failed to queue event\n");
+               res = AST_TEST_FAIL;
+               goto return_cleanup;
+       }
 
+       /*
+        * Event to check BITFLAGS matching.
+        *
+        * Matching subscriptions:
+        * TEST_SUBS_CUSTOM_BITFLAGS
+        * TEST_SUBS_CUSTOM_ANY
+        */
        event = ast_event_new(AST_EVENT_CUSTOM,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
-                       AST_EVENT_IE_END);
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_END);
        if (!event) {
                ast_test_status_update(test, "Failed to create event\n");
                res = AST_TEST_FAIL;
@@ -448,11 +802,18 @@ AST_TEST_DEFINE(event_sub_test)
                goto return_cleanup;
        }
 
+       /*
+        * Event to check EXISTS matching.
+        *
+        * Matching subscriptions:
+        * TEST_SUBS_CUSTOM_EXISTS
+        * TEST_SUBS_CUSTOM_BITFLAGS
+        * TEST_SUBS_CUSTOM_ANY
+        */
        event = ast_event_new(AST_EVENT_CUSTOM,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "800 km", strlen("800 km"),
-                       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 3,
-                       AST_EVENT_IE_END);
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_END);
        if (!event) {
                ast_test_status_update(test, "Failed to create event\n");
                res = AST_TEST_FAIL;
@@ -466,11 +827,24 @@ AST_TEST_DEFINE(event_sub_test)
                goto return_cleanup;
        }
 
+       /*
+        * Event to get dynamic subscription to have an event.
+        *
+        * Matching subscriptions:
+        * TEST_SUBS_CUSTOM_DYNAMIC
+        * TEST_SUBS_CUSTOM_BITFLAGS
+        * TEST_SUBS_CUSTOM_EXISTS
+        * TEST_SUBS_ALL_STR
+        * TEST_SUBS_CUSTOM_STR
+        * TEST_SUBS_CUSTOM_ANY
+        */
        event = ast_event_new(AST_EVENT_CUSTOM,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "blah",
-                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "801 km", strlen("801 km"),
-                       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 0,
-                       AST_EVENT_IE_END);
+               AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, 4,
+               AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, 5,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_RAW, "800 km", strlen("800 km"),
+               AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "FOO/bar",
+               AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, 5,
+               AST_EVENT_IE_END);
        if (!event) {
                ast_test_status_update(test, "Failed to create event\n");
                res = AST_TEST_FAIL;
@@ -483,6 +857,7 @@ AST_TEST_DEFINE(event_sub_test)
                res = AST_TEST_FAIL;
                goto return_cleanup;
        }
+
        event = NULL;
 
        /*
@@ -494,19 +869,23 @@ AST_TEST_DEFINE(event_sub_test)
         * If something was actually blocking event distribution that long, I would call
         * it a bug.
         *
-        * Expected results:
-        *  - sub 1, 2 events
-        *  - sub 2, 1 event
-        *  - sub 3, 2 events
+        * See test_subs[] initialization for expected results.
         */
 
        ast_test_status_update(test, "Sleeping a few seconds to allow event propagation...\n");
        sleep(3);
 
        for (i = 0; i < ARRAY_LEN(test_subs); i++) {
+               if (!test_subs[i].sub) {
+                       ast_test_status_update(test, "Missing a test subscription for %s\n",
+                               test_subs_class_type_str(i));
+                       res = AST_TEST_FAIL;
+               }
                if (test_subs[i].data.count != test_subs[i].expected_count) {
-                       ast_test_status_update(test, "Unexpected callback count, %u != %u for #%d\n",
-                                       test_subs[i].data.count, test_subs[i].expected_count, i);
+                       ast_test_status_update(test,
+                               "Unexpected callback count, got %u expected %u for %s\n",
+                               test_subs[i].data.count, test_subs[i].expected_count,
+                               test_subs_class_type_str(i));
                        res = AST_TEST_FAIL;
                }
        }