882 lines
26 KiB
C
882 lines
26 KiB
C
|
/*
|
||
|
* Asterisk -- An open source telephony toolkit.
|
||
|
*
|
||
|
* Copyright (C) 2014, Digium, Inc.
|
||
|
*
|
||
|
* Matt Jordan <mjordan@digium.com>
|
||
|
*
|
||
|
* See http://www.asterisk.org for more information about
|
||
|
* the Asterisk project. Please do not directly contact
|
||
|
* any of the maintainers of this project for assistance;
|
||
|
* the project provides a web site, mailing lists and IRC
|
||
|
* channels for your use.
|
||
|
*
|
||
|
* This program is free software, distributed under the terms of
|
||
|
* the GNU General Public License Version 2. See the LICENSE file
|
||
|
* at the top of the source tree.
|
||
|
*/
|
||
|
|
||
|
/*! \file
|
||
|
*
|
||
|
* \brief Test module for out-of-call text message module
|
||
|
*
|
||
|
* \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
|
||
|
*
|
||
|
* \ingroup tests
|
||
|
*/
|
||
|
|
||
|
/*** MODULEINFO
|
||
|
<depend>TEST_FRAMEWORK</depend>
|
||
|
<support_level>core</support_level>
|
||
|
***/
|
||
|
|
||
|
#include "asterisk.h"
|
||
|
|
||
|
#include <regex.h>
|
||
|
|
||
|
#include "asterisk/module.h"
|
||
|
#include "asterisk/test.h"
|
||
|
#include "asterisk/message.h"
|
||
|
#include "asterisk/pbx.h"
|
||
|
#include "asterisk/manager.h"
|
||
|
#include "asterisk/vector.h"
|
||
|
|
||
|
#define TEST_CATEGORY "/main/message/"
|
||
|
|
||
|
#define TEST_CONTEXT "__TEST_MESSAGE_CONTEXT__"
|
||
|
#define TEST_EXTENSION "test_message_extension"
|
||
|
|
||
|
/*! \brief The number of user events we should get in a dialplan test */
|
||
|
#define DEFAULT_EXPECTED_EVENTS 4
|
||
|
|
||
|
/*! \brief The current number of received user events */
|
||
|
static int received_user_events;
|
||
|
|
||
|
/*! \brief The number of user events we expect for this test */
|
||
|
static int expected_user_events;
|
||
|
|
||
|
/*! \brief Predicate for the \ref test_msg_handler receiving a message */
|
||
|
static int handler_received_message;
|
||
|
|
||
|
/*! \brief Condition wait variable for all dialplan user events being received */
|
||
|
static ast_cond_t user_event_cond;
|
||
|
|
||
|
/*! \brief Mutex for \c user_event_cond */
|
||
|
AST_MUTEX_DEFINE_STATIC(user_event_lock);
|
||
|
|
||
|
/*! \brief Condition wait variable for \ref test_msg_handler receiving message */
|
||
|
static ast_cond_t handler_cond;
|
||
|
|
||
|
/*! \brief Mutex for \c handler_cond */
|
||
|
AST_MUTEX_DEFINE_STATIC(handler_lock);
|
||
|
|
||
|
/*! \brief The expected user event fields */
|
||
|
AST_VECTOR(var_vector, struct ast_variable *) expected_user_event_fields;
|
||
|
|
||
|
/*! \brief If a user event fails, the bad headers that didn't match */
|
||
|
AST_VECTOR(, struct ast_variable *) bad_headers;
|
||
|
|
||
|
static int test_msg_send(const struct ast_msg *msg, const char *to, const char *from);
|
||
|
|
||
|
static struct ast_msg_tech test_msg_tech = {
|
||
|
.name = "testmsg",
|
||
|
.msg_send = test_msg_send,
|
||
|
};
|
||
|
|
||
|
static int test_msg_handle_msg_cb(struct ast_msg *msg);
|
||
|
static int test_msg_has_destination_cb(const struct ast_msg *msg);
|
||
|
|
||
|
/*! \brief Our test message handler */
|
||
|
static struct ast_msg_handler test_msg_handler = {
|
||
|
.name = "testmsg",
|
||
|
.handle_msg = test_msg_handle_msg_cb,
|
||
|
.has_destination = test_msg_has_destination_cb,
|
||
|
};
|
||
|
|
||
|
static int user_event_hook_cb(int category, const char *event, char *body);
|
||
|
|
||
|
/*! \brief AMI event hook that verifies whether or not we've gotten our user events */
|
||
|
static struct manager_custom_hook user_event_hook = {
|
||
|
.file = AST_MODULE,
|
||
|
.helper = user_event_hook_cb,
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
* \brief Verifies a user event header/value pair
|
||
|
*
|
||
|
* \param user_event which user event to check
|
||
|
* \param header The header to verify
|
||
|
* \param value The value read from the event
|
||
|
*
|
||
|
* \retval -1 on error or evaluation failure
|
||
|
* \retval 0 if match not needed or success
|
||
|
*/
|
||
|
static int verify_user_event_fields(int user_event, const char *header, const char *value)
|
||
|
{
|
||
|
struct ast_variable *current;
|
||
|
struct ast_variable *expected;
|
||
|
regex_t regexbuf;
|
||
|
int error;
|
||
|
|
||
|
if (user_event >= AST_VECTOR_SIZE(&expected_user_event_fields)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
expected = AST_VECTOR_GET(&expected_user_event_fields, user_event);
|
||
|
if (!expected) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
for (current = expected; current; current = current->next) {
|
||
|
struct ast_variable *bad_header;
|
||
|
|
||
|
if (strcmp(current->name, header)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
error = regcomp(®exbuf, current->value, REG_EXTENDED | REG_NOSUB);
|
||
|
if (error) {
|
||
|
char error_buf[128];
|
||
|
regerror(error, ®exbuf, error_buf, sizeof(error_buf));
|
||
|
ast_log(LOG_ERROR, "Failed to compile regex '%s' for header check '%s': %s\n",
|
||
|
current->value, current->name, error_buf);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (!regexec(®exbuf, value, 0, NULL, 0)) {
|
||
|
regfree(®exbuf);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bad_header = ast_variable_new(header, value, __FILE__);
|
||
|
if (bad_header) {
|
||
|
struct ast_variable *bad_headers_head = NULL;
|
||
|
|
||
|
if (user_event < AST_VECTOR_SIZE(&bad_headers)) {
|
||
|
bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event);
|
||
|
}
|
||
|
ast_variable_list_append(&bad_headers_head, bad_header);
|
||
|
AST_VECTOR_REPLACE(&bad_headers, user_event, bad_headers_head);
|
||
|
}
|
||
|
regfree(®exbuf);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int message_received;
|
||
|
|
||
|
static int test_msg_send(const struct ast_msg *msg, const char *to, const char *from)
|
||
|
{
|
||
|
message_received = 1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int test_msg_handle_msg_cb(struct ast_msg *msg)
|
||
|
{
|
||
|
ast_mutex_lock(&handler_lock);
|
||
|
handler_received_message = 1;
|
||
|
ast_cond_signal(&handler_cond);
|
||
|
ast_mutex_unlock(&handler_lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int test_msg_has_destination_cb(const struct ast_msg *msg)
|
||
|
{
|
||
|
/* We only care about one destination: foo! */
|
||
|
if (ast_strlen_zero(ast_msg_get_to(msg))) {
|
||
|
return 0;
|
||
|
}
|
||
|
return (!strcmp(ast_msg_get_to(msg), "foo") ? 1 : 0);
|
||
|
}
|
||
|
|
||
|
static int user_event_hook_cb(int category, const char *event, char *body)
|
||
|
{
|
||
|
char *parse;
|
||
|
char *kvp;
|
||
|
|
||
|
if (strcmp(event, "UserEvent")) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
parse = ast_strdupa(body);
|
||
|
while ((kvp = strsep(&parse, "\r\n"))) {
|
||
|
char *key, *value;
|
||
|
|
||
|
kvp = ast_trim_blanks(kvp);
|
||
|
if (ast_strlen_zero(kvp)) {
|
||
|
continue;
|
||
|
}
|
||
|
key = strsep(&kvp, ":");
|
||
|
value = ast_skip_blanks(kvp);
|
||
|
verify_user_event_fields(received_user_events, key, value);
|
||
|
}
|
||
|
|
||
|
received_user_events++;
|
||
|
|
||
|
ast_mutex_lock(&user_event_lock);
|
||
|
if (received_user_events == expected_user_events) {
|
||
|
ast_cond_signal(&user_event_cond);
|
||
|
}
|
||
|
ast_mutex_unlock(&user_event_lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*! \brief Wait for the \ref test_msg_handler to receive the message */
|
||
|
static int handler_wait_for_message(struct ast_test *test)
|
||
|
{
|
||
|
int error = 0;
|
||
|
struct timeval wait = ast_tvadd(ast_tvnow(), ast_tv(5 /* seconds */, 0));
|
||
|
struct timespec wait_time = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000 };
|
||
|
|
||
|
ast_mutex_lock(&handler_lock);
|
||
|
while (!handler_received_message) {
|
||
|
error = ast_cond_timedwait(&handler_cond, &handler_lock, &wait_time);
|
||
|
if (error == ETIMEDOUT) {
|
||
|
ast_test_status_update(test, "Test timed out while waiting for handler to get message\n");
|
||
|
ast_test_set_result(test, AST_TEST_FAIL);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ast_mutex_unlock(&handler_lock);
|
||
|
|
||
|
return (error != ETIMEDOUT);
|
||
|
}
|
||
|
|
||
|
/*! \brief Wait for the expected number of user events to be received */
|
||
|
static int user_event_wait_for_events(struct ast_test *test, int expected_events)
|
||
|
{
|
||
|
int error;
|
||
|
struct timeval wait = ast_tvadd(ast_tvnow(), ast_tv(5 /* seconds */, 0));
|
||
|
struct timespec wait_time = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000 };
|
||
|
|
||
|
expected_user_events = expected_events;
|
||
|
|
||
|
ast_mutex_lock(&user_event_lock);
|
||
|
while (received_user_events != expected_user_events) {
|
||
|
error = ast_cond_timedwait(&user_event_cond, &user_event_lock, &wait_time);
|
||
|
if (error == ETIMEDOUT) {
|
||
|
ast_test_status_update(test, "Test timed out while waiting for %d expected user events\n", expected_events);
|
||
|
ast_test_set_result(test, AST_TEST_FAIL);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ast_mutex_unlock(&user_event_lock);
|
||
|
|
||
|
ast_test_status_update(test, "Received %d of %d user events\n", received_user_events, expected_events);
|
||
|
return !(received_user_events == expected_events);
|
||
|
}
|
||
|
|
||
|
static int verify_bad_headers(struct ast_test *test)
|
||
|
{
|
||
|
int res = 0;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < AST_VECTOR_SIZE(&bad_headers); i++) {
|
||
|
struct ast_variable *headers;
|
||
|
struct ast_variable *current;
|
||
|
|
||
|
headers = AST_VECTOR_GET(&bad_headers, i);
|
||
|
if (!headers) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
res = -1;
|
||
|
for (current = headers; current; current = current->next) {
|
||
|
ast_test_status_update(test, "Expected UserEvent %d: Failed to match %s: %s\n",
|
||
|
i, current->name, current->value);
|
||
|
ast_test_set_result(test, AST_TEST_FAIL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_msg_tech_registration)
|
||
|
{
|
||
|
int reg_result;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test register/unregister of a message tech";
|
||
|
info->description =
|
||
|
"Test that:\n"
|
||
|
"\tA message technology can be registered once only\n"
|
||
|
"\tA registered message technology can be unregistered once only";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
reg_result = ast_msg_tech_register(&test_msg_tech);
|
||
|
ast_test_validate(test, reg_result == 0);
|
||
|
|
||
|
reg_result = ast_msg_tech_register(&test_msg_tech);
|
||
|
ast_test_validate(test, reg_result == -1);
|
||
|
|
||
|
reg_result = ast_msg_tech_unregister(&test_msg_tech);
|
||
|
ast_test_validate(test, reg_result == 0);
|
||
|
|
||
|
reg_result = ast_msg_tech_unregister(&test_msg_tech);
|
||
|
ast_test_validate(test, reg_result == -1);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_msg_handler_registration)
|
||
|
{
|
||
|
int reg_result;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test register/unregister of a message handler";
|
||
|
info->description =
|
||
|
"Test that:\n"
|
||
|
"\tA message handler can be registered once only\n"
|
||
|
"\tA registered message handler can be unregistered once only";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
reg_result = ast_msg_handler_register(&test_msg_handler);
|
||
|
ast_test_validate(test, reg_result == 0);
|
||
|
|
||
|
reg_result = ast_msg_handler_register(&test_msg_handler);
|
||
|
ast_test_validate(test, reg_result == -1);
|
||
|
|
||
|
reg_result = ast_msg_handler_unregister(&test_msg_handler);
|
||
|
ast_test_validate(test, reg_result == 0);
|
||
|
|
||
|
reg_result = ast_msg_handler_unregister(&test_msg_handler);
|
||
|
ast_test_validate(test, reg_result == -1);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
static void ast_msg_safe_destroy(void *obj)
|
||
|
{
|
||
|
struct ast_msg *msg = obj;
|
||
|
|
||
|
if (msg) {
|
||
|
ast_msg_destroy(msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_manipulation)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
RAII_VAR(struct ast_msg_var_iterator *, it_vars, NULL, ast_msg_var_iterator_destroy);
|
||
|
int result;
|
||
|
const char *actual;
|
||
|
const char *out_name;
|
||
|
const char *out_value;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test manipulating properties of a message";
|
||
|
info->description =
|
||
|
"This test covers the following:\n"
|
||
|
"\tSetting/getting the body\n"
|
||
|
"\tSetting/getting inbound/outbound variables\n"
|
||
|
"\tIterating over variables";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
/* Test setting/getting to */
|
||
|
result = ast_msg_set_to(msg, "testmsg:%s", "foo");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_to(msg);
|
||
|
ast_test_validate(test, !strcmp(actual, "testmsg:foo"));
|
||
|
|
||
|
/* Test setting/getting from */
|
||
|
result = ast_msg_set_from(msg, "testmsg:%s", "bar");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_from(msg);
|
||
|
ast_test_validate(test, !strcmp(actual, "testmsg:bar"));
|
||
|
|
||
|
/* Test setting/getting body */
|
||
|
result = ast_msg_set_body(msg, "BodyTest: %s", "foo");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_body(msg);
|
||
|
ast_test_validate(test, !strcmp(actual, "BodyTest: foo"));
|
||
|
|
||
|
/* Test setting/getting technology */
|
||
|
result = ast_msg_set_tech(msg, "%s", "my_tech");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_tech(msg);
|
||
|
ast_test_validate(test, !strcmp(actual, "my_tech"));
|
||
|
|
||
|
/* Test setting/getting endpoint */
|
||
|
result = ast_msg_set_endpoint(msg, "%s", "terminus");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_endpoint(msg);
|
||
|
ast_test_validate(test, !strcmp(actual, "terminus"));
|
||
|
|
||
|
/* Test setting/getting non-outbound variable */
|
||
|
result = ast_msg_set_var(msg, "foo", "bar");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_var(msg, "foo");
|
||
|
ast_test_validate(test, !strcmp(actual, "bar"));
|
||
|
|
||
|
/* Test updating existing variable */
|
||
|
result = ast_msg_set_var(msg, "foo", "new_bar");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
actual = ast_msg_get_var(msg, "foo");
|
||
|
ast_test_validate(test, !strcmp(actual, "new_bar"));
|
||
|
|
||
|
/* Verify a non-outbound variable is not iterable */
|
||
|
it_vars = ast_msg_var_iterator_init(msg);
|
||
|
ast_test_validate(test, it_vars != NULL);
|
||
|
ast_test_validate(test, ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value) == 0);
|
||
|
ast_msg_var_iterator_destroy(it_vars);
|
||
|
|
||
|
/* Test updating an existing variable as an outbound variable */
|
||
|
result = ast_msg_set_var_outbound(msg, "foo", "outbound_bar");
|
||
|
ast_test_validate(test, result == 0);
|
||
|
it_vars = ast_msg_var_iterator_init(msg);
|
||
|
ast_test_validate(test, it_vars != NULL);
|
||
|
result = ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value);
|
||
|
ast_test_validate(test, result == 1);
|
||
|
ast_test_validate(test, !strcmp(out_name, "foo"));
|
||
|
ast_test_validate(test, !strcmp(out_value, "outbound_bar"));
|
||
|
ast_msg_var_unref_current(it_vars);
|
||
|
result = ast_msg_var_iterator_next(msg, it_vars, &out_name, &out_value);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_queue_dialplan_nominal)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
struct ast_variable *expected;
|
||
|
struct ast_variable *expected_response = NULL;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test enqueueing messages to the dialplan";
|
||
|
info->description =
|
||
|
"Test that a message enqueued for the dialplan is\n"
|
||
|
"passed to that particular extension";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
expected = ast_variable_new("Verify","^To$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value","^foo$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response);
|
||
|
|
||
|
expected_response = NULL;
|
||
|
expected = ast_variable_new("Verify", "^From$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value","^bar$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response);
|
||
|
|
||
|
expected_response = NULL;
|
||
|
expected = ast_variable_new("Verify", "^Body$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value", "^a body$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response);
|
||
|
|
||
|
expected_response = NULL;
|
||
|
expected = ast_variable_new("Verify", "^Custom$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value", "^field$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 3, expected_response);
|
||
|
|
||
|
ast_msg_set_to(msg, "foo");
|
||
|
ast_msg_set_from(msg, "bar");
|
||
|
ast_msg_set_body(msg, "a body");
|
||
|
ast_msg_set_var_outbound(msg, "custom_data", "field");
|
||
|
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, TEST_EXTENSION);
|
||
|
|
||
|
ast_msg_queue(msg);
|
||
|
msg = NULL;
|
||
|
|
||
|
if (user_event_wait_for_events(test, DEFAULT_EXPECTED_EVENTS)) {
|
||
|
ast_test_status_update(test, "Failed to received %d expected user events\n", DEFAULT_EXPECTED_EVENTS);
|
||
|
return AST_TEST_FAIL;
|
||
|
}
|
||
|
|
||
|
if (verify_bad_headers(test)) {
|
||
|
return AST_TEST_FAIL;
|
||
|
}
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_queue_handler_nominal)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
int result;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test enqueueing messages to a handler";
|
||
|
info->description =
|
||
|
"Test that a message enqueued can be handled by a\n"
|
||
|
"non-dialplan handler";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
result = ast_msg_handler_register(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
ast_msg_set_to(msg, "foo");
|
||
|
ast_msg_set_from(msg, "bar");
|
||
|
ast_msg_set_body(msg, "a body");
|
||
|
|
||
|
ast_msg_queue(msg);
|
||
|
msg = NULL;
|
||
|
|
||
|
/* This will automatically fail the test if we don't get the message */
|
||
|
handler_wait_for_message(test);
|
||
|
|
||
|
result = ast_msg_handler_unregister(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_queue_both_nominal)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
struct ast_variable *expected;
|
||
|
struct ast_variable *expected_response = NULL;
|
||
|
int result;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test enqueueing messages to a dialplan and custom handler";
|
||
|
info->description =
|
||
|
"Test that a message enqueued is passed to all\n"
|
||
|
"handlers that can process it, dialplan as well as\n"
|
||
|
"a custom handler";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
result = ast_msg_handler_register(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
expected = ast_variable_new("Verify","^To$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value","^foo$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 0, expected_response);
|
||
|
|
||
|
expected_response = NULL;
|
||
|
expected = ast_variable_new("Verify", "^From$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value","^bar$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 1, expected_response);
|
||
|
|
||
|
expected_response = NULL;
|
||
|
expected = ast_variable_new("Verify", "^Body$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
expected = ast_variable_new("Value", "^a body$", __FILE__);
|
||
|
ast_variable_list_append(&expected_response, expected);
|
||
|
AST_VECTOR_REPLACE(&expected_user_event_fields, 2, expected_response);
|
||
|
|
||
|
ast_msg_set_to(msg, "foo");
|
||
|
ast_msg_set_from(msg, "bar");
|
||
|
ast_msg_set_body(msg, "a body");
|
||
|
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, TEST_EXTENSION);
|
||
|
|
||
|
ast_msg_queue(msg);
|
||
|
msg = NULL;
|
||
|
|
||
|
if (user_event_wait_for_events(test, DEFAULT_EXPECTED_EVENTS)) {
|
||
|
ast_test_status_update(test, "Failed to received %d expected user events\n", DEFAULT_EXPECTED_EVENTS);
|
||
|
ast_test_set_result(test, AST_TEST_FAIL);
|
||
|
}
|
||
|
|
||
|
/* This will automatically fail the test if we don't get the message */
|
||
|
handler_wait_for_message(test);
|
||
|
|
||
|
result = ast_msg_handler_unregister(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
if (verify_bad_headers(test)) {
|
||
|
return AST_TEST_FAIL;
|
||
|
}
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_has_destination_dialplan)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test checking for a dialplan destination";
|
||
|
info->description =
|
||
|
"Test that a message's destination is verified via the\n"
|
||
|
"dialplan";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, TEST_EXTENSION);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 1);
|
||
|
|
||
|
ast_msg_set_context(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 0);
|
||
|
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 0);
|
||
|
|
||
|
ast_msg_set_exten(msg, NULL);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 0);
|
||
|
|
||
|
ast_msg_set_context(msg, NULL);
|
||
|
ast_msg_set_exten(msg, TEST_EXTENSION);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 0);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_has_destination_handler)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
int result;
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test checking for a handler destination";
|
||
|
info->description =
|
||
|
"Test that a message's destination is verified via a\n"
|
||
|
"handler";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
result = ast_msg_handler_register(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
ast_msg_set_to(msg, "foo");
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, NULL);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 1);
|
||
|
|
||
|
ast_msg_set_context(msg, NULL);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 1);
|
||
|
|
||
|
ast_msg_set_to(msg, "__I_SHOULD_NOT_EXIST_PLZ__");
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 0);
|
||
|
|
||
|
result = ast_msg_handler_unregister(&test_msg_handler);
|
||
|
ast_test_validate(test, result == 0);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
AST_TEST_DEFINE(test_message_msg_send)
|
||
|
{
|
||
|
RAII_VAR(struct ast_msg *, msg, NULL, ast_msg_safe_destroy);
|
||
|
|
||
|
switch (cmd) {
|
||
|
case TEST_INIT:
|
||
|
info->name = __func__;
|
||
|
info->category = TEST_CATEGORY;
|
||
|
info->summary = "Test message routing";
|
||
|
info->description =
|
||
|
"Test that a message can be routed if it has\n"
|
||
|
"a valid handler";
|
||
|
return AST_TEST_NOT_RUN;
|
||
|
case TEST_EXECUTE:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ast_test_validate(test, ast_msg_tech_register(&test_msg_tech) == 0);
|
||
|
ast_test_validate(test, ast_msg_handler_register(&test_msg_handler) == 0);
|
||
|
|
||
|
msg = ast_msg_alloc();
|
||
|
ast_test_validate(test, msg != NULL);
|
||
|
|
||
|
ast_msg_set_to(msg, "foo");
|
||
|
ast_msg_set_context(msg, TEST_CONTEXT);
|
||
|
ast_msg_set_exten(msg, NULL);
|
||
|
ast_test_validate(test, ast_msg_has_destination(msg) == 1);
|
||
|
|
||
|
if (!ast_msg_send(msg, "testmsg:foo", "blah")) {
|
||
|
msg = NULL;
|
||
|
} else {
|
||
|
ast_test_status_update(test, "Failed to send message\n");
|
||
|
ast_test_set_result(test, AST_TEST_FAIL);
|
||
|
}
|
||
|
|
||
|
ast_test_validate(test, ast_msg_handler_unregister(&test_msg_handler) == 0);
|
||
|
ast_test_validate(test, ast_msg_tech_unregister(&test_msg_tech) == 0);
|
||
|
|
||
|
return AST_TEST_PASS;
|
||
|
}
|
||
|
|
||
|
static int test_init_cb(struct ast_test_info *info, struct ast_test *test)
|
||
|
{
|
||
|
received_user_events = 0;
|
||
|
handler_received_message = 0;
|
||
|
message_received = 0;
|
||
|
|
||
|
AST_VECTOR_INIT(&expected_user_event_fields, DEFAULT_EXPECTED_EVENTS);
|
||
|
AST_VECTOR_INIT(&bad_headers, DEFAULT_EXPECTED_EVENTS);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define FREE_VARIABLE_VECTOR(vector) do { \
|
||
|
int i; \
|
||
|
for (i = 0; i < AST_VECTOR_SIZE(&(vector)); i++) { \
|
||
|
struct ast_variable *headers; \
|
||
|
headers = AST_VECTOR_GET(&(vector), i); \
|
||
|
if (!headers) { \
|
||
|
continue; \
|
||
|
} \
|
||
|
ast_variables_destroy(headers); \
|
||
|
} \
|
||
|
AST_VECTOR_FREE(&(vector)); \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
static int test_cleanup_cb(struct ast_test_info *info, struct ast_test *test)
|
||
|
{
|
||
|
FREE_VARIABLE_VECTOR(expected_user_event_fields);
|
||
|
FREE_VARIABLE_VECTOR(bad_headers);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int unload_module(void)
|
||
|
{
|
||
|
AST_TEST_UNREGISTER(test_message_msg_tech_registration);
|
||
|
AST_TEST_UNREGISTER(test_message_msg_handler_registration);
|
||
|
AST_TEST_UNREGISTER(test_message_manipulation);
|
||
|
AST_TEST_UNREGISTER(test_message_queue_dialplan_nominal);
|
||
|
AST_TEST_UNREGISTER(test_message_queue_handler_nominal);
|
||
|
AST_TEST_UNREGISTER(test_message_queue_both_nominal);
|
||
|
AST_TEST_UNREGISTER(test_message_has_destination_dialplan);
|
||
|
AST_TEST_UNREGISTER(test_message_has_destination_handler);
|
||
|
AST_TEST_UNREGISTER(test_message_msg_send);
|
||
|
|
||
|
ast_context_destroy(NULL, AST_MODULE);
|
||
|
|
||
|
ast_manager_unregister_hook(&user_event_hook);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int create_test_dialplan(void)
|
||
|
{
|
||
|
int res = 0;
|
||
|
|
||
|
if (!ast_context_find_or_create(NULL, NULL, TEST_CONTEXT, AST_MODULE)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 1, NULL, NULL,
|
||
|
"UserEvent", "TestMessageUnitTest,Verify:To,Value:${MESSAGE(to)}",
|
||
|
NULL, AST_MODULE);
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 2, NULL, NULL,
|
||
|
"UserEvent", "TestMessageUnitTest,Verify:From,Value:${MESSAGE(from)}",
|
||
|
NULL, AST_MODULE);
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 3, NULL, NULL,
|
||
|
"UserEvent", "TestMessageUnitTest,Verify:Body,Value:${MESSAGE(body)}",
|
||
|
NULL, AST_MODULE);
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 4, NULL, NULL,
|
||
|
"UserEvent", "TestMessageUnitTest,Verify:Custom,Value:${MESSAGE_DATA(custom_data)}",
|
||
|
NULL, AST_MODULE);
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 5, NULL, NULL,
|
||
|
"Set", "MESSAGE_DATA(custom_data)=${MESSAGE_DATA(custom_data)}",
|
||
|
NULL, AST_MODULE);
|
||
|
res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 6, NULL, NULL,
|
||
|
"MessageSend", "testmsg:${MESSAGE(from)},testmsg:${MESSAGE(to)}",
|
||
|
NULL, AST_MODULE);
|
||
|
|
||
|
ast_manager_register_hook(&user_event_hook);
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static int load_module(void)
|
||
|
{
|
||
|
AST_TEST_REGISTER(test_message_msg_tech_registration);
|
||
|
AST_TEST_REGISTER(test_message_msg_handler_registration);
|
||
|
AST_TEST_REGISTER(test_message_manipulation);
|
||
|
AST_TEST_REGISTER(test_message_queue_dialplan_nominal);
|
||
|
AST_TEST_REGISTER(test_message_queue_handler_nominal);
|
||
|
AST_TEST_REGISTER(test_message_queue_both_nominal);
|
||
|
AST_TEST_REGISTER(test_message_has_destination_dialplan);
|
||
|
AST_TEST_REGISTER(test_message_has_destination_handler);
|
||
|
AST_TEST_REGISTER(test_message_msg_send);
|
||
|
|
||
|
create_test_dialplan();
|
||
|
|
||
|
ast_test_register_init(TEST_CATEGORY, test_init_cb);
|
||
|
ast_test_register_cleanup(TEST_CATEGORY, test_cleanup_cb);
|
||
|
|
||
|
return AST_MODULE_LOAD_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Out-of-call text message support");
|