From dbdb2b1b3a618a79b3e42c77c05cb2688b4da08d Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Tue, 11 Jun 2013 15:46:35 +0000 Subject: [PATCH] Add vtable and methods for to_json and to_ami for Stasis messages When a Stasis message type is defined in a loadable module, handling those messages for AMI and res_stasis events can be cumbersome. This patch adds a vtable to stasis_message_type, with to_ami and to_json virtual functions. These allow messages to be handled abstractly without putting module-specific code in core. As an example, the VarSet AMI event was refactored to use the to_ami virtual function. (closes issue ASTERISK-21817) Review: https://reviewboard.asterisk.org/r/2579/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391403 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/stasis.h | 121 +++++++++++++++++---- main/manager.c | 35 +++++- main/manager_channels.c | 48 -------- main/parking.c | 12 +- main/stasis_channels.c | 94 ++++++++++++---- main/stasis_message.c | 34 +++++- tests/test_stasis.c | 205 ++++++++++++++++++++++++++++++++--- tests/test_stasis_channels.c | 4 +- 8 files changed, 432 insertions(+), 121 deletions(-) diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h index 6a55d09267..bd303ebd8d 100644 --- a/include/asterisk/stasis.h +++ b/include/asterisk/stasis.h @@ -154,6 +154,8 @@ * certain loads. */ +#include "asterisk/json.h" +#include "asterisk/manager.h" #include "asterisk/utils.h" /*! @{ */ @@ -165,17 +167,58 @@ struct stasis_message_type; /*! - * \brief Register a new message type. + * \brief Opaque type for a Stasis message. + * \since 12 + */ +struct stasis_message; + +/*! + * \brief Virtual table providing methods for messages. + * \since 12 + */ +struct stasis_message_vtable { + /*! + * \brief Build the JSON representation of the message. + * + * May be \c NULL, or may return \c NULL, to indicate no representation. + * The returned object should be ast_json_unref()'ed. + * + * \param message Message to convert to JSON string. + * \return Newly allocated JSON message. + * \return \c NULL on error. + * \return \c NULL if JSON format is not supported. + */ + struct ast_json *(*to_json)(struct stasis_message *message); + + /*! + * \brief Build the AMI representation of the message. + * + * May be \c NULL, or may return \c NULL, to indicate no representation. + * The returned object should be ao2_cleankup()'ed. + * + * \param message Message to convert to AMI string. + * \return Newly allocated \ref ast_manager_event_blob. + * \return \c NULL on error. + * \return \c NULL if AMI format is not supported. + */ + struct ast_manager_event_blob *(*to_ami)( + struct stasis_message *message); +}; + +/*! + * \brief Create a new message type. * * \ref stasis_message_type is an AO2 object, so ao2_cleanup() when you're done * with it. * * \param name Name of the new type. + * \param vtable Virtual table of message methods. May be \c NULL. * \return Pointer to the new type. * \return \c NULL on error. * \since 12 */ -struct stasis_message_type *stasis_message_type_create(const char *name); +struct stasis_message_type *stasis_message_type_create(const char *name, + struct stasis_message_vtable *vtable); /*! * \brief Gets the name of a given message type @@ -186,12 +229,6 @@ struct stasis_message_type *stasis_message_type_create(const char *name); */ const char *stasis_message_type_name(const struct stasis_message_type *type); -/*! - * \brief Opaque type for a Stasis message. - * \since 12 - */ -struct stasis_message; - /*! * \brief Create a new message. * @@ -234,6 +271,32 @@ void *stasis_message_data(const struct stasis_message *msg); */ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg); +/*! + * \brief Build the JSON representation of the message. + * + * May return \c NULL, to indicate no representation. The returned object should + * be ast_json_unref()'ed. + * + * \param message Message to convert to JSON string. + * \return Newly allocated string with JSON message. + * \return \c NULL on error. + * \return \c NULL if JSON format is not supported. + */ +struct ast_json *stasis_message_to_json(struct stasis_message *message); + +/*! + * \brief Build the AMI representation of the message. + * + * May return \c NULL, to indicate no representation. The returned object should + * be ao2_cleanup()'ed. + * + * \param message Message to convert to AMI. + * \return \c NULL on error. + * \return \c NULL if AMI format is not supported. + */ +struct ast_manager_event_blob *stasis_message_to_ami( + struct stasis_message *message); + /*! @} */ /*! @{ */ @@ -635,20 +698,37 @@ void stasis_log_bad_type_access(const char *name); /*! * \brief Boiler-plate removing macro for defining message types. * + * \code + * STASIS_MESSAGE_TYPE_DEFN(ast_foo_type, + * .to_ami = foo_to_ami, + * .to_json = foo_to_json, + * ); + * \endcode + * * \param name Name of message type. - * \since 12 - */ -#define STASIS_MESSAGE_TYPE_DEFN(name) \ - static struct stasis_message_type *_priv_ ## name; \ - struct stasis_message_type *name(void) { \ - if (_priv_ ## name == NULL) { \ - stasis_log_bad_type_access(#name); \ - } \ - return _priv_ ## name; \ + * \param ... Virtual table methods for messages of this type. + * \since 12 + */ +#define STASIS_MESSAGE_TYPE_DEFN(name, ...) \ + static struct stasis_message_vtable _priv_ ## name ## _v = { \ + __VA_ARGS__ \ + }; \ + static struct stasis_message_type *_priv_ ## name; \ + struct stasis_message_type *name(void) { \ + if (_priv_ ## name == NULL) { \ + stasis_log_bad_type_access(#name); \ + } \ + return _priv_ ## name; \ } /*! - * \brief Boiler-plate removing macro for initializing message types. +* \brief Boiler-plate removing macro for initializing message types. + * + * \code + * if (STASIS_MESSAGE_TYPE_INIT(ast_foo_type) != 0) { + * return -1; + * } + * \endcode * * \param name Name of message type. * \return 0 if initialization is successful. @@ -658,8 +738,9 @@ void stasis_log_bad_type_access(const char *name); #define STASIS_MESSAGE_TYPE_INIT(name) \ ({ \ ast_assert(_priv_ ## name == NULL); \ - _priv_ ## name = stasis_message_type_create(#name); \ - _priv_ ## name ? 0 : -1; \ + _priv_ ## name = stasis_message_type_create(#name, \ + &_priv_ ## name ## _v); \ + _priv_ ## name ? 0 : -1; \ }) /*! diff --git a/main/manager.c b/main/manager.c index b8e55de4f3..eb01cc536f 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1313,6 +1313,23 @@ struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_excl return output_str; } +static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, + struct stasis_topic *topic, + struct stasis_message *message) +{ + RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + + ev = stasis_message_to_ami(message); + + if (ev == NULL) { + /* Not and AMI message; disregard */ + return; + } + + manager_event(ev->event_flags, ev->manager_event, "%s", + ev->extra_fields); +} + static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message) @@ -7686,7 +7703,12 @@ static void manager_shutdown(void) */ static int manager_subscriptions_init(void) { - STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type); + int res; + + res = STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type); + if (res != 0) { + return -1; + } manager_topic = stasis_topic_create("manager_topic"); if (!manager_topic) { return -1; @@ -7696,10 +7718,13 @@ static int manager_subscriptions_init(void) return -1; } - if (stasis_message_router_add(stasis_router, - ast_manager_get_generic_type(), - manager_generic_msg_cb, - NULL)) { + res |= stasis_message_router_set_default(stasis_router, + manager_default_msg_cb, NULL); + + res |= stasis_message_router_add(stasis_router, + ast_manager_get_generic_type(), manager_generic_msg_cb, NULL); + + if (res != 0) { return -1; } return 0; diff --git a/main/manager_channels.c b/main/manager_channels.c index b6eeb60b07..277dc873d8 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -710,49 +710,6 @@ static void channel_snapshot_update(void *data, struct stasis_subscription *sub, } } -static void channel_varset_cb(void *data, struct stasis_subscription *sub, - struct stasis_topic *topic, struct stasis_message *message) -{ - struct ast_channel_blob *obj = stasis_message_data(message); - RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); - const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable")); - const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value")); - - if (obj->snapshot) { - channel_event_string = ast_manager_build_channel_state_string(obj->snapshot); - } else { - channel_event_string = ast_str_create(35); - ast_str_set(&channel_event_string, 0, - "Channel: none\r\n" - "Uniqueid: none\r\n"); - } - - if (!channel_event_string) { - return; - } - - /*** DOCUMENTATION - - Raised when a variable is set to a particular value. - - - - The variable being set. - - - The new value of the variable. - - - - ***/ - manager_event(EVENT_FLAG_DIALPLAN, "VarSet", - "%s" - "Variable: %s\r\n" - "Value: %s\r\n", - ast_str_buffer(channel_event_string), - variable, value); -} - static int userevent_exclusion_cb(const char *key) { if (!strcmp("type", key)) { @@ -1279,11 +1236,6 @@ int manager_channels_init(void) channel_snapshot_update, NULL); - ret |= stasis_message_router_add(message_router, - ast_channel_varset_type(), - channel_varset_cb, - NULL); - ret |= stasis_message_router_add(message_router, ast_channel_user_event_type(), channel_user_event_cb, diff --git a/main/parking.c b/main/parking.c index 2a5b72e61f..a7cd0ba54e 100644 --- a/main/parking.c +++ b/main/parking.c @@ -35,7 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/channel.h" /*! \brief Message type for parked calls */ -static struct stasis_message_type *parked_call_type; +STASIS_MESSAGE_TYPE_DEFN(ast_parked_call_type); /*! \brief Topic for parking lots */ static struct stasis_topic *parking_topic; @@ -48,15 +48,14 @@ static ast_bridge_channel_park_fn ast_bridge_channel_park_func = NULL; void ast_parking_stasis_init(void) { - parked_call_type = stasis_message_type_create("ast_parked_call"); + STASIS_MESSAGE_TYPE_INIT(ast_parked_call_type); parking_topic = stasis_topic_create("ast_parking"); } void ast_parking_stasis_disable(void) { - ao2_cleanup(parked_call_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_parked_call_type); ao2_cleanup(parking_topic); - parked_call_type = NULL; parking_topic = NULL; } @@ -65,11 +64,6 @@ struct stasis_topic *ast_parking_topic(void) return parking_topic; } -struct stasis_message_type *ast_parked_call_type(void) -{ - return parked_call_type; -} - /*! \brief Destructor for parked_call_payload objects */ static void parked_call_payload_destructor(void *obj) { diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 65e9f917dd..8327384d7a 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -36,29 +36,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/stasis_channels.h" -#define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7 +/*** DOCUMENTATION + + + Raised when a variable is set to a particular value. + + + + The variable being set. + + + The new value of the variable. + + + + +***/ -/*! - * @{ \brief Define channel message types. - */ -STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type); -STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type); -/*! @} */ +#define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7 /*! \brief Topic for all channels */ struct stasis_topic *channel_topic_all; @@ -540,6 +535,36 @@ void ast_channel_publish_varset(struct ast_channel *chan, const char *name, cons ast_channel_publish_blob(chan, ast_channel_varset_type(), blob); } +static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg) +{ + RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); + struct ast_channel_blob *obj = stasis_message_data(msg); + const char *variable = + ast_json_string_get(ast_json_object_get(obj->blob, "variable")); + const char *value = + ast_json_string_get(ast_json_object_get(obj->blob, "value")); + + if (obj->snapshot) { + channel_event_string = + ast_manager_build_channel_state_string(obj->snapshot); + } else { + channel_event_string = ast_str_create(35); + ast_str_set(&channel_event_string, 0, + "Channel: none\r\n" + "Uniqueid: none\r\n"); + } + + if (!channel_event_string) { + return NULL; + } + + return ast_manager_event_blob_create(EVENT_FLAG_DIALPLAN, "VarSet", + "%s" + "Variable: %s\r\n" + "Value: %s\r\n", + ast_str_buffer(channel_event_string), variable, value); +} + void ast_publish_channel_state(struct ast_channel *chan) { RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); @@ -626,6 +651,31 @@ int ast_channel_snapshot_caller_id_equal( strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0; } +/*! + * @{ \brief Define channel message types. + */ +STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type, + .to_ami = varset_to_ami, + ); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type); +STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type); + +/*! @} */ + static void stasis_channels_cleanup(void) { channel_topic_all_cached = stasis_caching_unsubscribe_and_join(channel_topic_all_cached); diff --git a/main/stasis_message.c b/main/stasis_message.c index 8d2373f4db..b25d1f25a3 100644 --- a/main/stasis_message.c +++ b/main/stasis_message.c @@ -37,9 +37,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") /*! \internal */ struct stasis_message_type { + struct stasis_message_vtable *vtable; char *name; }; +static struct stasis_message_vtable null_vtable = {}; + static void message_type_dtor(void *obj) { struct stasis_message_type *type = obj; @@ -47,7 +50,8 @@ static void message_type_dtor(void *obj) type->name = NULL; } -struct stasis_message_type *stasis_message_type_create(const char *name) +struct stasis_message_type *stasis_message_type_create(const char *name, + struct stasis_message_vtable *vtable) { RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); @@ -55,11 +59,16 @@ struct stasis_message_type *stasis_message_type_create(const char *name) if (!type) { return NULL; } + if (!vtable) { + /* Null object pattern, FTW! */ + vtable = &null_vtable; + } type->name = ast_strdup(name); if (!type->name) { return NULL; } + type->vtable = vtable; ao2_ref(type, +1); return type; @@ -133,3 +142,26 @@ const struct timeval *stasis_message_timestamp(const struct stasis_message *msg) } return &msg->timestamp; } + +#define INVOKE_VIRTUAL(fn, ...) \ + ({ \ + if (msg == NULL) { \ + return NULL; \ + } \ + ast_assert(msg->type != NULL); \ + ast_assert(msg->type->vtable != NULL); \ + if (msg->type->vtable->fn == NULL) { \ + return NULL; \ + } \ + msg->type->vtable->fn(__VA_ARGS__); \ + }) + +struct ast_manager_event_blob *stasis_message_to_ami(struct stasis_message *msg) +{ + return INVOKE_VIRTUAL(to_ami, msg); +} + +struct ast_json *stasis_message_to_json(struct stasis_message *msg) +{ + return INVOKE_VIRTUAL(to_json, msg); +} diff --git a/tests/test_stasis.c b/tests/test_stasis.c index 915226d293..0dc9182a33 100644 --- a/tests/test_stasis.c +++ b/tests/test_stasis.c @@ -41,6 +41,34 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static const char *test_category = "/stasis/core/"; +static struct ast_json *fake_json(struct stasis_message *message) +{ + const char *text = stasis_message_data(message); + + return ast_json_string_create(text); +} + +static struct ast_manager_event_blob *fake_ami(struct stasis_message *message) +{ + RAII_VAR(struct ast_manager_event_blob *, res, NULL, ao2_cleanup); + const char *text = stasis_message_data(message); + + res = ast_manager_event_blob_create(EVENT_FLAG_TEST, "FakeMI", + "Message: %s", text); + + if (res == NULL) { + return NULL; + } + + ao2_ref(res, +1); + return res; +} + +static struct stasis_message_vtable fake_vtable = { + .to_json = fake_json, + .to_ami = fake_ami +}; + AST_TEST_DEFINE(message_type) { RAII_VAR(struct stasis_message_type *, uut, NULL, ao2_cleanup); @@ -56,8 +84,8 @@ AST_TEST_DEFINE(message_type) break; } - ast_test_validate(test, NULL == stasis_message_type_create(NULL)); - uut = stasis_message_type_create("SomeMessage"); + ast_test_validate(test, NULL == stasis_message_type_create(NULL, NULL)); + uut = stasis_message_type_create("SomeMessage", NULL); ast_test_validate(test, 0 == strcmp(stasis_message_type_name(uut), "SomeMessage")); return AST_TEST_PASS; @@ -84,7 +112,7 @@ AST_TEST_DEFINE(message) } - type = stasis_message_type_create("SomeMessage"); + type = stasis_message_type_create("SomeMessage", NULL); ast_test_validate(test, NULL == stasis_message_create(NULL, NULL)); ast_test_validate(test, NULL == stasis_message_create(type, NULL)); @@ -332,7 +360,7 @@ AST_TEST_DEFINE(publish) test_data = ao2_alloc(1, NULL); ast_test_validate(test, NULL != test_data); - test_message_type = stasis_message_type_create("TestMessage"); + test_message_type = stasis_message_type_create("TestMessage", NULL); test_message = stasis_message_create(test_message_type, test_data); stasis_publish(topic, test_message); @@ -380,7 +408,7 @@ AST_TEST_DEFINE(unsubscribe_stops_messages) test_data = ao2_alloc(1, NULL); ast_test_validate(test, NULL != test_data); - test_message_type = stasis_message_type_create("TestMessage"); + test_message_type = stasis_message_type_create("TestMessage", NULL); test_message = stasis_message_create(test_message_type, test_data); stasis_publish(topic, test_message); @@ -444,7 +472,7 @@ AST_TEST_DEFINE(forward) test_data = ao2_alloc(1, NULL); ast_test_validate(test, NULL != test_data); - test_message_type = stasis_message_type_create("TestMessage"); + test_message_type = stasis_message_type_create("TestMessage", NULL); test_message = stasis_message_create(test_message_type, test_data); stasis_publish(topic, test_message); @@ -494,7 +522,7 @@ AST_TEST_DEFINE(interleaving) break; } - test_message_type = stasis_message_type_create("test"); + test_message_type = stasis_message_type_create("test", NULL); ast_test_validate(test, NULL != test_message_type); test_data = ao2_alloc(1, NULL); @@ -604,7 +632,7 @@ AST_TEST_DEFINE(cache_passthrough) break; } - non_cache_type = stasis_message_type_create("NonCacheable"); + non_cache_type = stasis_message_type_create("NonCacheable", NULL); ast_test_validate(test, NULL != non_cache_type); topic = stasis_topic_create("SomeTopic"); ast_test_validate(test, NULL != topic); @@ -657,7 +685,7 @@ AST_TEST_DEFINE(cache) break; } - cache_type = stasis_message_type_create("Cacheable"); + cache_type = stasis_message_type_create("Cacheable", NULL); ast_test_validate(test, NULL != cache_type); topic = stasis_topic_create("SomeTopic"); ast_test_validate(test, NULL != topic); @@ -759,7 +787,7 @@ AST_TEST_DEFINE(cache_dump) break; } - cache_type = stasis_message_type_create("Cacheable"); + cache_type = stasis_message_type_create("Cacheable", NULL); ast_test_validate(test, NULL != cache_type); topic = stasis_topic_create("SomeTopic"); ast_test_validate(test, NULL != topic); @@ -866,7 +894,7 @@ AST_TEST_DEFINE(route_conflicts) consumer2 = consumer_create(1); ast_test_validate(test, NULL != consumer2); - test_message_type = stasis_message_type_create("TestMessage"); + test_message_type = stasis_message_type_create("TestMessage", NULL); ast_test_validate(test, NULL != test_message_type); uut = stasis_message_router_create(topic); @@ -920,11 +948,11 @@ AST_TEST_DEFINE(router) consumer3 = consumer_create(1); ast_test_validate(test, NULL != consumer3); - test_message_type1 = stasis_message_type_create("TestMessage1"); + test_message_type1 = stasis_message_type_create("TestMessage1", NULL); ast_test_validate(test, NULL != test_message_type1); - test_message_type2 = stasis_message_type_create("TestMessage2"); + test_message_type2 = stasis_message_type_create("TestMessage2", NULL); ast_test_validate(test, NULL != test_message_type2); - test_message_type3 = stasis_message_type_create("TestMessage3"); + test_message_type3 = stasis_message_type_create("TestMessage3", NULL); ast_test_validate(test, NULL != test_message_type3); uut = stasis_message_router_create(topic); @@ -978,6 +1006,147 @@ AST_TEST_DEFINE(router) return AST_TEST_PASS; } +AST_TEST_DEFINE(no_to_json) +{ + RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup); + RAII_VAR(char *, data, NULL, ao2_cleanup); + RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref); + char *expected = "SomeData"; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test message to_json function"; + info->description = "Test message to_json function"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* Test NULL */ + actual = stasis_message_to_json(NULL); + ast_test_validate(test, NULL == actual); + + /* Test message with NULL to_json function */ + type = stasis_message_type_create("SomeMessage", NULL); + + data = ao2_alloc(strlen(expected) + 1, NULL); + strcpy(data, expected); + uut = stasis_message_create(type, data); + ast_test_validate(test, NULL != uut); + + actual = stasis_message_to_json(uut); + ast_test_validate(test, NULL == actual); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(to_json) +{ + RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup); + RAII_VAR(char *, data, NULL, ao2_cleanup); + RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref); + const char *expected_text = "SomeData"; + RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref); + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test message to_json function when NULL"; + info->description = "Test message to_json function when NULL"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + type = stasis_message_type_create("SomeMessage", &fake_vtable); + + data = ao2_alloc(strlen(expected_text) + 1, NULL); + strcpy(data, expected_text); + uut = stasis_message_create(type, data); + ast_test_validate(test, NULL != uut); + + expected = ast_json_string_create(expected_text); + actual = stasis_message_to_json(uut); + ast_test_validate(test, ast_json_equal(expected, actual)); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(no_to_ami) +{ + RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup); + RAII_VAR(char *, data, NULL, ao2_cleanup); + RAII_VAR(struct ast_manager_event_blob *, actual, NULL, ao2_cleanup); + char *expected = "SomeData"; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test message to_ami function when NULL"; + info->description = "Test message to_ami function when NULL"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* Test NULL */ + actual = stasis_message_to_ami(NULL); + ast_test_validate(test, NULL == actual); + + /* Test message with NULL to_ami function */ + type = stasis_message_type_create("SomeMessage", NULL); + + data = ao2_alloc(strlen(expected) + 1, NULL); + strcpy(data, expected); + uut = stasis_message_create(type, data); + ast_test_validate(test, NULL != uut); + + actual = stasis_message_to_ami(uut); + ast_test_validate(test, NULL == actual); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(to_ami) +{ + RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, uut, NULL, ao2_cleanup); + RAII_VAR(char *, data, NULL, ao2_cleanup); + RAII_VAR(struct ast_manager_event_blob *, actual, NULL, ao2_cleanup); + const char *expected_text = "SomeData"; + const char *expected = "Message: SomeData"; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test message to_ami function"; + info->description = "Test message to_ami function"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + type = stasis_message_type_create("SomeMessage", &fake_vtable); + + data = ao2_alloc(strlen(expected_text) + 1, NULL); + strcpy(data, expected_text); + uut = stasis_message_create(type, data); + ast_test_validate(test, NULL != uut); + + actual = stasis_message_to_ami(uut); + ast_test_validate(test, strcmp(expected, actual->extra_fields) == 0); + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(message_type); @@ -992,6 +1161,10 @@ static int unload_module(void) AST_TEST_UNREGISTER(route_conflicts); AST_TEST_UNREGISTER(router); AST_TEST_UNREGISTER(interleaving); + AST_TEST_UNREGISTER(no_to_json); + AST_TEST_UNREGISTER(to_json); + AST_TEST_UNREGISTER(no_to_ami); + AST_TEST_UNREGISTER(to_ami); return 0; } @@ -1009,6 +1182,10 @@ static int load_module(void) AST_TEST_REGISTER(route_conflicts); AST_TEST_REGISTER(router); AST_TEST_REGISTER(interleaving); + AST_TEST_REGISTER(no_to_json); + AST_TEST_REGISTER(to_json); + AST_TEST_REGISTER(no_to_ami); + AST_TEST_REGISTER(to_ami); return AST_MODULE_LOAD_SUCCESS; } diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c index 512df43514..214d773963 100644 --- a/tests/test_stasis_channels.c +++ b/tests/test_stasis_channels.c @@ -71,7 +71,7 @@ AST_TEST_DEFINE(channel_blob_create) break; } - type = stasis_message_type_create("test-type"); + type = stasis_message_type_create("test-type", NULL); chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice"); json = ast_json_pack("{s: s}", "foo", "bar"); @@ -123,7 +123,7 @@ AST_TEST_DEFINE(null_blob) break; } - type = stasis_message_type_create("test-type"); + type = stasis_message_type_create("test-type", NULL); chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice"); json = ast_json_pack("{s: s}", "foo", "bar");